<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>developer_key.log</title>
        <link>https://velog.io/</link>
        <description>발전하는 프론트엔드 개발자</description>
        <lastBuildDate>Tue, 28 Dec 2021 08:01:29 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>developer_key.log</title>
            <url>https://images.velog.io/images/developer_key/profile/7c9f3e55-af7b-4584-9557-8f79f29faa9b/순례자의길.jpeg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. developer_key.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/developer_key" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[Cypress SSR API intercept 처리법]]></title>
            <link>https://velog.io/@developer_key/Cypress-SSR-API-intercept-%EC%B2%98%EB%A6%AC%EB%B2%95</link>
            <guid>https://velog.io/@developer_key/Cypress-SSR-API-intercept-%EC%B2%98%EB%A6%AC%EB%B2%95</guid>
            <pubDate>Tue, 28 Dec 2021 08:01:29 GMT</pubDate>
            <description><![CDATA[<p>Cypress 테스트 코드 작성 중 SSR에서 호출하는 API는 intercept가 안되는 현상이 있어서 해결하는데 고생좀 했다.</p>
<p>결론은 Cypress 전용 NextJS 서버를 하나 더 만들어주고 nock 라이브러리를 통해 api를 mock data로 바꿔주면 된다.</p>
<p>cypress/plugins/index.js 에 다음과 같이 작성해주자.</p>
<pre><code>const nock = require(&#39;nock&#39;);
const next = require(&#39;next&#39;);
const express = require(&#39;express&#39;);

const CYPRESS_SERVER_PORT = 3000;

// start the Next.js server when Cypress starts
module.exports = async (on, config) =&gt; {
  const app = next({ dev: true });
  const handle = app.getRequestHandler();

  app
    .prepare()
    .then(() =&gt; {
      const server = express();

      server.get(&#39;*&#39;, (req, res) =&gt; {
        return handle(req, res);
      });

      server.listen(CYPRESS_SERVER_PORT, () =&gt; {
        console.warn(`SSR server running, client path is http://localhost:${CYPRESS_SERVER_PORT}`);
      });
    })
    .catch(ex =&gt; {
      console.error(&#39;ex&#39;, ex.stack);
      process.exit(1);
    });

  // register handlers for cy.task command
  // https://on.cypress.io/task
  on(&#39;task&#39;, {
    clearNock() {
      nock.restore();
      nock.cleanAll();

      return null;
    },

    async nock({ hostname, method, path, statusCode, body }) {
      nock.activate();

      console.log(
        &#39;nock will: %s %s%s respond with %d %o&#39;,
        method,
        hostname,
        path,
        statusCode,
        body,
      );

      // add one-time network stub like
      // nock(&#39;https://icanhazdadjoke.com&#39;).get(&#39;/&#39;).reply(200, ...)
      method = method.toLowerCase();
      nock(hostname)
        [method](path)
        .reply(statusCode, body);

      return null;
    },
  });

  return config;
};</code></pre><p>사용법은 다음과 같다. body에 mock data를 넣어주자.</p>
<pre><code>import projectDetail from &#39;../../fixtures/project/projectDetail&#39;;

describe(&#39;상세페이지&#39;, () =&gt; {
  beforeEach(() =&gt; {
    cy.task(&#39;clearNock&#39;);
  });

  context(&#39;기본&#39;, () =&gt; {
    before(&#39;&#39;, () =&gt; {});

    it(&#39;랜더 체크&#39;, () =&gt; {
      cy.task(&#39;nock&#39;, {
        hostname: Cypress.env(&#39;API_URL&#39;),
        method: &#39;GET&#39;,
        path: &#39;/api/v2/projects/2000&#39;,
        statusCode: 200,
        body: projectDetail,
      });
      cy.visit(&#39;/projects/2000&#39;);
    });
  });
});</code></pre><p>cypress 버전은 다음과 같다.
&quot;cypress&quot;: &quot;^9.1.1&quot;,</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Nextjs SSG 가지고 놀기]]></title>
            <link>https://velog.io/@developer_key/Nextjs-SSG-%EA%B0%80%EC%A7%80%EA%B3%A0-%EB%86%80%EA%B8%B0</link>
            <guid>https://velog.io/@developer_key/Nextjs-SSG-%EA%B0%80%EC%A7%80%EA%B3%A0-%EB%86%80%EA%B8%B0</guid>
            <pubDate>Mon, 22 Mar 2021 13:34:29 GMT</pubDate>
            <description><![CDATA[<p>요즘 이녀석에 대해 소홀했나보다.. 버전 업데이트만 해놓고 그저 SSR를 위해 한다고 생각했으니...</p>
<p>뭐 공식문서에서도</p>
<h4 id="recommended-getstaticprops-or-getserversideprops">Recommended: getStaticProps or getServerSideProps.</h4>
<p>If you&#39;re using Next.js 9.3 or newer, we recommend that you use getStaticProps or getServerSideProps instead of getInitialProps.</p>
<p>이걸 쓰라고 하니 차근차근 바꿔나가는 작업이 필요해 보인다.</p>
<p>공식문서와 nextjs 관련 이슈들을 읽다보니 우리 프로젝트에는 어떻게 적용시킬 수 있을까? 고민이 많이 들었다.</p>
<p>공식 문서를 살표보니 SSG는 유저의 요청에 관계없이 같은 화면을 보여줘도 상관없을 때, 쓰라고하는걸 보니 상세페이지들에 사용하면 되겠다 싶었다. (매번 같은 api를 호출 하니깐 !?)</p>
<p>이것저것 해보고 싶은 마음이 생겨 무작정 프로젝트를 하나 만들어 보며 이것저것 해보았다.</p>
<p>뭐 대충 회사 API를 활용하여 다음과 같이 페이지 하나를 만들어 보았다.</p>
<pre><code>import axios from &quot;axios&quot;;

const Detail = ({ happyfolio }) =&gt; {
  return happyfolio ? (
    &lt;div&gt;
      &lt;div&gt;{happyfolio.id}&lt;/div&gt;
      &lt;div&gt;{happyfolio.title}&lt;/div&gt;
    &lt;/div&gt;
  ) : (
    &lt;span&gt;No happyfolio&lt;/span&gt;
  );
};

export const getStaticPaths = async () =&gt; {
  return {
    paths: [{ params: { id: &quot;8&quot; } }],
    fallback: true,
  };
};

export const getStaticProps = async (context) =&gt; {
  try {
    const { data } = await axios.get(
      `http://localhost:8080/api/v2/happyfolios/${context.params.id}`
    );
    return {
      props: { happyfolio: data },
    };
  } catch (err) {
    console.log(&quot;err&quot;, err);
  }

  return {
    props: {},
  };
};

export default Detail;</code></pre><p>이제 빌드를 해볼까 </p>
<p><img src="https://images.velog.io/images/developer_key/post/d3b9ab3a-4efa-48e9-9f68-35f0f864ccd8/1.png" alt=""></p>
<p><img src="https://images.velog.io/images/developer_key/post/c50dc026-5497-48c5-ae67-eb787f789412/%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%202021-03-22%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%2010.26.08.png" alt=""></p>
<p><img src="https://images.velog.io/images/developer_key/post/78592e6b-7a17-4a55-951d-88f5638d5a2f/%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%202021-03-22%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%2010.26.43.png" alt=""></p>
<p>.next/pages/detail에 
8.html, 8.json 파일이 생겼다! </p>
<p>getStaticPaths에 params로 전달해줬던 id값들을 읽고 다음과 같이 정적파일들을 만들어 준것이다.</p>
<p>Home화면에는 다음과 같이 여러 링크들을 넣어보았다.</p>
<pre><code>import Link from &quot;next/link&quot;;

const Home = () =&gt; {
  return (
    &lt;div&gt;
      hello next
      &lt;Link href=&quot;/about&quot;&gt;about&lt;/Link&gt;
      &lt;Link href=&quot;/sample&quot;&gt;sample&lt;/Link&gt;
      &lt;Link href=&quot;/detail/5&quot;&gt;5&lt;/Link&gt;
      &lt;Link href=&quot;/detail/6&quot;&gt;6&lt;/Link&gt;
      &lt;Link href=&quot;/detail/7&quot; prefetch={false}&gt;
        7
      &lt;/Link&gt;
      &lt;Link href=&quot;/detail/8&quot;&gt;8&lt;/Link&gt;
    &lt;/div&gt;
  );
};

export default Home;</code></pre><p><img src="https://images.velog.io/images/developer_key/post/3e31f258-3b9e-49f1-a7f5-3cc731e39a78/%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%202021-03-22%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%2010.28.54.png" alt=""></p>
<p>next start 실행 후 메인페이지에 접속해보니, Link들의 prefetch로 인해</p>
<p><img src="https://images.velog.io/images/developer_key/post/053074e6-554f-4ac3-b49d-534fc17e18eb/%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%202021-03-22%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%2010.30.59.png" alt=""></p>
<p>5,6 html, json 파일이 추가로 생긴것을 볼 수 있었다.
fallback을 true로 설정해주면 params로 getStaticProps에 전달해주지 않아도 최초 request시 해당 파일들을 생성해주는건가보다.</p>
<p>7번 파일은 Link 태그의 attr 중 prefetch={false}로 인해 정적 파일을 pre-render 하지 않은 모양이구</p>
<p>다음엔 getServerSideProps에 대해 알아봐야겠다.
getInitialProps와 어떤게 다르고 어떤 점이 더 좋아졌는지 말이다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[20210322 - NextJS SSG관련 이슈]]></title>
            <link>https://velog.io/@developer_key/20210322-NextJS-SSG%EA%B4%80%EB%A0%A8-%EC%9D%B4%EC%8A%88</link>
            <guid>https://velog.io/@developer_key/20210322-NextJS-SSG%EA%B4%80%EB%A0%A8-%EC%9D%B4%EC%8A%88</guid>
            <pubDate>Mon, 22 Mar 2021 13:04:10 GMT</pubDate>
            <description><![CDATA[<p>최근 SSG 도입을 위해 Nextjs의 getStaticProps를 적극 활용해 보고 있다. 관련 문서들을 정독하고 있는데(한글 자료가 별로 없음 ㅜ)</p>
<h3 id="이슈-1-page에서-store-접근">이슈 1. page에서 store 접근</h3>
<p>기존 페이지 getInitialProps에서는 app.tsx에서 next-redux-wrapper에서 redux를 연결시켜주어 context에서 store에 접근이 가능하였지만, SSG를 위해서는 page 마다 따로 연결시켜줘야 하나보다.. </p>
<p>요런식으로 </p>
<pre><code>export const getStaticProps = wrapper.getStaticProps(async context =&gt; {
  return { props: {} };
});</code></pre><h3 id="이슈-2-hydrate-관련-문제">이슈 2. hydrate 관련 문제</h3>
<p>분명 SSG에서도 store에 접근이 가능하다고 했는데, 왜 store에 저장이 안되지 ? 혹시 안되는건가... 하고 유심히 코드를 뒤져보았다. 
hydrate 이놈 .. SSR을 도입하면서 골머리를 썩였던놈</p>
<p>찾아보던 중 우리 enhancedReducer에서 이상한 점을 찾았다.</p>
<pre><code>  if (action.type === HYDRATE) {
    if (state === initialRootState) {
      return {
        ...state,
        ...action.payload,
      };
    }
    return state;
  }</code></pre><p>으음 .. if (state === initialRootState) 이녀석은 왜 필요한거지 관련 자료를 찾아 
다음과 같이 수정해 주었다.</p>
<pre><code> if (action.type === HYDRATE) {
    const nextState = {
      ...state, // use previous state
      ...action.payload, // apply delta from hydration
    };
    return nextState;
  }</code></pre><p>잘 작동한다. 아마 Hydrate가 필요없는 상황에서 실행되는게 싫어서 저렇게 처리한것 같다.
기존 코드에 문제가 생길 수 있으니 관련 테스트가 좀 필요해보인다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[20210322- NextJS SSG 도입]]></title>
            <link>https://velog.io/@developer_key/20210322-NextJS-SSG-%EB%8F%84%EC%9E%85</link>
            <guid>https://velog.io/@developer_key/20210322-NextJS-SSG-%EB%8F%84%EC%9E%85</guid>
            <pubDate>Mon, 22 Mar 2021 12:43:57 GMT</pubDate>
            <description><![CDATA[<p>20210322</p>
<p>최근 NextJS에 대해 제대로 공부하고 있다.
그저 단순히 사용하는것이 아니라 왜 SSR, SSG를 이용하는지, 어떻게 해야 효율적으로 이용할 수 있는지 등등..</p>
<p>오늘 처음으로 회사 프로젝트 상세페이지에 SSG를 적용시켜 보았다.</p>
<pre><code>export const getStaticPaths = async () =&gt; {
  return {
    paths: [{ params: { id: &#39;16&#39; } }],
    fallback: true,
  };
};</code></pre><p>build시 /event/16 HTML파일과 JSON파일이 잘 생성되고, 동적 라우팅에서 params로 설정해 주지 않아도 최초 request시 HTML, JSON이 잘생기는것 또한 확인하였다. SSG의 엄청난 스피드에 감탄하며 아직 미흡한 부분을 확인하고 있다.</p>
<p>가장 큰 이슈는 기존에 _app.tsx getInitialProps에서 SSR으로 로그인을 진행하였는데, SSG 페이지에서는 SSR이 실행되지 않는다는 것이다.</p>
<p>흠.. 그래서 SSG페이지에서 새로고침시에 로그인이 풀려버린다. 
client side에서 로그인 시켜주는 방법으로 해결을 하였지만, express-session에서 http-only로 인해 client-side에서 access_token을 가져오지 못하여, 불필요한 api 호출이 생기게 되었다.(access_token이 있을때만 로그인 api를 호출하고 싶음... 있는지만 체크하고 싶은데 해결 방법 아시는 분?)</p>
<p>관련 문서들을 좀 더 찾아보고 가장 효율적인 방법으로 도입해야겠다.</p>
]]></description>
        </item>
    </channel>
</rss>