<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>dev_hikun.log</title>
        <link>https://velog.io/</link>
        <description>디자인도 개발도 좋아하며 프론트엔더를 사칭하는 괴발자</description>
        <lastBuildDate>Thu, 13 May 2021 01:03:21 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>dev_hikun.log</title>
            <url>https://images.velog.io/images/dev_hikun/profile/b369d16e-8132-4eeb-955d-edd10166b6cd/social.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. dev_hikun.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/dev_hikun" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[Electron] Not allowed to load local resource in Renderer process Trouble Shooting]]></title>
            <link>https://velog.io/@dev_hikun/Electron-Not-allowed-to-load-local-resource-in-Renderer-process-Trouble-Shooting</link>
            <guid>https://velog.io/@dev_hikun/Electron-Not-allowed-to-load-local-resource-in-Renderer-process-Trouble-Shooting</guid>
            <pubDate>Thu, 13 May 2021 01:03:21 GMT</pubDate>
            <description><![CDATA[<p><img src="https://images.velog.io/images/dev_hikun/post/2cb01cd4-c47e-4852-929e-55e5f464dd29/notallowedtoloadlocalresource.png" alt="Electron Not allowed to load local resource 에러"></p>
<h4 id="not-allowed-to-load-local-resource-왜-로컬파일에-접근이-안되는거야">Not allowed to load local resource... 왜 로컬파일에 접근이 안되는거야!!!</h4>
<p>일하던 중 엄청난 난관에 부딪혔다..</p>
<p>개발환경에서는 아무런 문제가 없었으나 Electron Builder로 배포된 일렉트론 앱에서 문제가 발생하였다.</p>
<p>렌더러 프로세스(React)에서 로컬 파일에 접근하려고 하니, 아래와 같은 에러가 나타났다.</p>
<p>장장 2시간동안 구글링을 통해 이것저것 보았지만, 다들 이상한 방법 뿐이었다.</p>
<p>나는 초록색 체크표시가 있는 스택오버플로를 찾고싶었지만 찾을 수 없었다 ㅠ_ㅠ 망할 일렉트론..</p>
<p>그러다가 문득 이런 생각이 들었다.</p>
<blockquote>
<p>local resource에 File 프로토콜로 접근할 때 불가능 한 거 아닐까? 혹시 다른 방법으로 해결할 수 있지 않을까?</p>
</blockquote>
<p><strong>LUCKY</strong>. 맞았다.</p>
<p>일렉트론에서는 <a href="https://www.electronjs.org/docs/api/protocol#protocol">Protocol</a> API를 제공한다.</p>
<p>렌더러 (저의 경우에는 React 입니다.) 에서는 아래와 같이 호출해준다.</p>
<pre><code class="language-jsx">&lt;div
  style={{
    backgroundSize: &#39;contain&#39;,
    backgroundPosition: &#39;center&#39;,
    backgroundRepeat: &#39;no-repeat&#39;,
    backgroundImage: `url(&#39;safe-my-protocol://${path}&#39;)`,
  }}
  className=&quot;full-screen-img&quot;
/&gt;</code></pre>
<p>메인 프로세스에서는 아래와 같이 호출해준다.</p>
<pre><code class="language-javascript">protocol.registerFileProtocol(&#39;local&#39;, (request, callback) =&gt; {
    const pathname = decodeURIComponent(request.url.replace(&#39;safe-my-protocol://&#39;, &#39;&#39;));
    try {
      callback(pathname);
    } catch (error) {
      console.log(error);
    }
  });</code></pre>
<p>이렇게 하면 renderer에서의 Not allowed to load local resource문제를 해결하게 된다! 굿!</p>
<p><em>** 도움이 되셨다면 하트 한번만 부탁해요 :-) **</em></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React] 렌더시 깜빡거림 해결 Trouble shooting]]></title>
            <link>https://velog.io/@dev_hikun/React-%EB%A0%8C%EB%8D%94%EC%8B%9C-%EA%B9%9C%EB%B9%A1%EA%B1%B0%EB%A6%BC-%ED%95%B4%EA%B2%B0-Trouble-shooting</link>
            <guid>https://velog.io/@dev_hikun/React-%EB%A0%8C%EB%8D%94%EC%8B%9C-%EA%B9%9C%EB%B9%A1%EA%B1%B0%EB%A6%BC-%ED%95%B4%EA%B2%B0-Trouble-shooting</guid>
            <pubDate>Tue, 16 Mar 2021 08:56:18 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>2021-03-16. <strong>문제가 됐던 상황</strong></p>
</blockquote>
<br>

<p><img src="https://images.velog.io/images/dev_hikun/post/2dd5285a-fe74-4871-ac44-fa3fc116ac08/ezgif-6-721b4207a5d2.gif" alt="렌더 할 때 마다 깜빡거리는 이미지 사진"></p>
<h5 id="blob으로-불러온-이미지가-렌더가-일어-날-때마다-깜빡거렸다">Blob으로 불러온 이미지가 렌더가 일어 날 때마다 깜빡거렸다.</h5>
<br>
<br>

<blockquote>
<p><strong>FOUC</strong> <em>(Flash of Unstyld Content, 링크 사라짐)</em> </p>
</blockquote>
<br>

<p>이 에러를 해결하다 알게 된 단어인데, 무언가 처리되면서 DOM 요소가 반짝 거릴 경우를 FOUC라고 하는데, css의 스타일이 적용이 안되었는데 화면이 표시되거나 웹 폰트 등이 로딩이 되지 않았을 때 발생하는 화면 깜빡임을 말한다. 이번에는 <code>useEffect</code>에 의해 해당 깜빡임이 있었음을 알게 되었다.</p>
<p><strong><em>하지만 <code>useEffect</code>는 사용도 안하고 &quot;찾았다!&quot; 생각하고서는 글 쓰다가 아랫쪽에 <code>React.memo</code>를 사용했음을 알린다.</em></strong>
<br>
<br></p>
<blockquote>
<p><strong>useEffect</strong> vs <strong>useLayoutEffect</strong></p>
</blockquote>
<ul>
<li><p><strong>useEffect</strong></p>
<ul>
<li><p>렌더가 화면에 그려진 후 <strong>비동기적</strong>으로 실행</p>
<p>  ✨ 일부 state를 즉시 바꿔 렌더할 필요가 없을 경우</p>
<p>  ✨ 페이지에 시각적으로 영향을 주지 않는 무언가를 동기화 할 경우</p>
<p>  ✨ 이벤트 핸들러를 설정하는 경우</p>
<p>  ✨ 모달 상자가 나타나거나 사라질 때 일부 상태를 재설정하는 경우</p>
</li>
</ul>
</li>
<li><p><strong>useLayoutEffect</strong></p>
<ul>
<li><p>렌더링 후 화면이 업데이트 되기 전에 <strong>동기적</strong>으로 실행</p>
<p>  ✨ state가 업데이트 될 때 요소가 깜빡이는 경우</p>
<p>  ✨ DOM을 변경하려는 경우</p>
  <br>
  <br>

</li>
</ul>
</li>
</ul>
<blockquote>
<h2 id="하지만">하지만....</h2>
</blockquote>
<p>그런데.. 내 코드는 useEffect를 통한 깜빡임이 아니었다. </p>
<p>useState를 이용한 값을 set하면서 렌더가 되는 것이었다...</p>
<p>Setstate가 되더라도 렌더가 되지 않게끔 따로 설정을 해주어야 했고, 
그에 해당하는 함수로 <a href="https://ko.reactjs.org/docs/higher-order-components.html">HOC 방식</a> <del><strong><em>(제가 번역한 페이지에요!)</em></strong></del>의 <strong><code>React.memo</code></strong>를 사용하는 것이었다.</p>
<ul>
<li><a href="https://ko.reactjs.org/docs/react-api.html#reactmemo">React memo</a>의 자세한 내용은 해당 링크를 확인하면 될 것 같다.</li>
</ul>
<p>이미지 부분만 자식 컴포넌트로 뜯어내고, React.memo의 첫번째 인자로 넣어주고, 두번째 인자를 사용해 <strong>렌더를 할 지 안 할지</strong>를 결정하여 빤짝거림을 해결했다.</p>
<blockquote>
<p><strong>적용 결과</strong></p>
</blockquote>
<p><img src="https://images.velog.io/images/dev_hikun/post/96acbc9c-087f-4e70-8cf3-b9326c2d67e9/ezgif-4-f3ae4a1e0b27.gif" alt="더 이상 반짝이지 않는 이미지"></p>
<h6 id="이미지가-더이상-반짝이지-않음을-볼-수-있다">이미지가 더이상 반짝이지 않음을 볼 수 있다.</h6>
<p>오늘의 트러블 슈팅 끝!</p>
<hr>
<p>참조 사이트</p>
<ul>
<li><a href="https://kentcdodds.com/blog/useeffect-vs-uselayouteffect">useEffect vs useLayoutEffect</a></li>
<li><a href="https://dmitripavlutin.com/use-react-memo-wisely/">react memo를 현명하게 사용하기</a></li>
<li><a href="https://hikun.notion.site/React-Blob-b80232fbb7694f30a4c0b8e9aa1738a9">원본 노션 글</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[github 블로그 설치중 발생한 에러 해결]]></title>
            <link>https://velog.io/@dev_hikun/github-%EB%B8%94%EB%A1%9C%EA%B7%B8-%EC%84%A4%EC%B9%98%EC%A4%91-%EB%B0%9C%EC%83%9D%ED%95%9C-%EC%97%90%EB%9F%AC-%ED%95%B4%EA%B2%B0</link>
            <guid>https://velog.io/@dev_hikun/github-%EB%B8%94%EB%A1%9C%EA%B7%B8-%EC%84%A4%EC%B9%98%EC%A4%91-%EB%B0%9C%EC%83%9D%ED%95%9C-%EC%97%90%EB%9F%AC-%ED%95%B4%EA%B2%B0</guid>
            <pubDate>Mon, 15 Feb 2021 09:23:53 GMT</pubDate>
            <description><![CDATA[<h3 id="개발환경">개발환경</h3>
<p>os x catalina 10.15.7</p>
<hr>
<h3 id="발생-원인">발생 원인</h3>
<pre><code>$ bundle</code></pre><hr>
<h3 id="에러-메세지-일부">에러 메세지 (일부)</h3>
<pre><code>Gem::Ext::BuildError: ERROR: Failed to build gem native extension.</code></pre><pre><code>An error occurred while installing eventmachine (1.2.7), and Bundler
cannot continue.
Make sure that `gem install eventmachine -v &#39;1.2.7&#39; --source
&#39;https://rubygems.org/&#39;` succeeds before bundling.</code></pre><pre><code>current directory:
/Library/Ruby/Gems/2.6.0/gems/http_parser.rb-0.6.0/ext/ruby_http_parser
make &quot;DESTDIR=&quot;
make: *** No rule to make target
`/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/include/ruby-2.6.0/universal-darwin19/ruby/config.h&#39;,
needed by `ruby_http_parser.o&#39;.  Stop.

make failed, exit code 2</code></pre><p>등등 엄청난 에러가 발생. jekyll기반으로 만들어진 블로그가 설치가 안되는 상황이 발생</p>
<hr>
<h3 id="해결방법">해결방법</h3>
<pre><code class="language-SHELL">$ brew install ruby
$ brew link --overwrite ruby</code></pre>
<pre><code>If you need to have ruby first in your PATH, run:
  echo &#39;export PATH=&quot;/usr/local/opt/ruby/bin:$PATH&quot;&#39; &gt;&gt; ~/.zshrc

For compilers to find ruby you may need to set:
  export LDFLAGS=&quot;-L/usr/local/opt/ruby/lib&quot;
  export CPPFLAGS=&quot;-I/usr/local/opt/ruby/include&quot;</code></pre><p>zsh 쉘을 사용하기 때문에 ~/.zshrc에 설정하라고 위와 같은 메세지가 나온다.
쉘의 설정파일 안에 위 내용들을 추가해주면 된다.</p>
<p>bash 쉘을 사용한다면 ~/.bash_profile이라고 나옵니다.</p>
<hr>
<p><strong>참고 사이트</strong> : <a href="github.com/ffi/ffi/issues/653">github.com/ffi/ffi/issues/653</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Electron + React + typescript 데스크탑 앱 개발 시작해보기]]></title>
            <link>https://velog.io/@dev_hikun/Electron-React-typescript-%EB%8D%B0%EC%8A%A4%ED%81%AC%ED%83%91-%EC%95%B1-%EB%A7%8C%EB%93%A4%EA%B8%B0-1-%EC%84%A4%EC%B9%98-%EB%B0%8F-%EC%84%A4%EC%A0%95</link>
            <guid>https://velog.io/@dev_hikun/Electron-React-typescript-%EB%8D%B0%EC%8A%A4%ED%81%AC%ED%83%91-%EC%95%B1-%EB%A7%8C%EB%93%A4%EA%B8%B0-1-%EC%84%A4%EC%B9%98-%EB%B0%8F-%EC%84%A4%EC%A0%95</guid>
            <pubDate>Thu, 14 Jan 2021 06:54:12 GMT</pubDate>
            <description><![CDATA[<p>회사에서 윈도우프로그램과 웹 소켓으로 통신하는 데스크탑 프로그램을 만드는 프로젝트를 맡게 되었다.
(필자는 이 프로젝트를 시작함과 동시에 &#39;오예 벨로그에 쓸거 생겼다&#39; 라는 생각에 들떴다는건 비밀)</p>
<p>이에 본인의 기록용 포스팅이라는 베이스를 두고 누군가 필요한 사람을 위해 강좌 형식으로 적도록 하겠다.
<del>본디 기록용 포스팅 일 뿐이어서, 불친절한 시리즈인건 안비밀</del></p>
<h1 id="0-본-포스팅에-사용-된-버전">0. 본 포스팅에 사용 된 버전</h1>
<p>필자는 yarn이 아닌 npm을 주로 사용한다.</p>
<p><strong>사용된 버전</strong>
node:  v12.20.0
npm, npx:  v6.14.8
react : 17.0.1
electron-is-dev: 1.2.0
electron: 11.2.0
electron-builder: 22.9.1
typescript: 4.1.3
wait-on: 5.2.1
cross-env: 7.0.3
concurrently: 5.3.0</p>
<h1 id="1-react-app-생성">1. React App 생성</h1>
<pre><code>npx create-react-app 앱이름 --template typescript</code></pre><p>npm이 아닌 npx로 앱을 생성한다. npx를 사용하면 최신버전의 CRA로 React가 실행되는 환경을 만들 수 있다.
우리는 타입스크립트를 사용할 것이기 때문에 뒤에 뒤에 _<code>--template typescript</code>_는 필수.</p>
<blockquote>
<p><a href="https://velog.io/@kimkyeseung/%EB%B2%88%EC%97%AD-%EA%B7%B8%EB%9E%98-npx-npm%EB%A7%90%EA%B3%A0-%EC%B0%A8%EC%9D%B4%EC%A0%90-%EC%84%A4%EB%AA%85">참조: npm과 npx의 차이점</a></p>
</blockquote>
<h1 id="2-electron-설치">2. Electron 설치</h1>
<p>react 프로젝트가 성공적으로 생성 되었다면, 
해당 앱 폴더로 이동하여 Electron과 각종 개발에 편의성을 주는 도구들을 설치한다.</p>
<pre><code>npm i electron-is-dev
npm i electron electron-builder concurrently cross-env wait-on typescript --save-dev</code></pre><p>해당 모듈들은 (electron-is-dev 제외) 런타임에서 사용되지 않을 개발용 모듈이므로 <em><code>--save-dev</code></em> 인수를 추가해준다.</p>
<ul>
<li><strong><code>Electron-is-dev</code></strong>: 개발환경인지 빌드한 프로덕션환경인지 확인을 위하여 사용됨.</li>
<li><strong><code>Electron</code></strong> : 일렉트론을 실행하기 위해서 사용됨.</li>
<li><strong><code>Electron-builder</code></strong> : 일렉트론을 실제 프로덕션 버전으로 빌드하기 위해 사용됨.</li>
<li><strong><code>concurrently</code></strong> : 동시에 여러 명령어를 사용(병렬적으로)하기 위해 사용됨.</li>
<li><strong><code>cross-env</code></strong> : 프로그램을 CLI환경에서 실행 시킬 때에, OS에 관계 없이 환경변수를 설정할 수 있도록 하기 위해 사용됨.</li>
<li><a href="https://github.com/jeffbski/wait-on#readme"><strong><code>wait-on</code></strong></a> : HTTP 자원, port, file등이 활성화 될 때 까지 기다려주는 cross platform</li>
<li><strong><code>typescript</code></strong> : typescript</li>
</ul>
<p><del>tsconfig는 각자 알아서 작성하시길....</del></p>
<h1 id="3-electron을-실행하는-코드작성">3. Electron을 실행하는 코드작성</h1>
<p>위에서 모든것이 완료되었다면, public 폴더 안에 Electron을 실행하는 ts파일을 하나 작성해준다.</p>
<pre><code class="language-TYPESCRIPT">import { app, BrowserWindow } from &#39;electron&#39;;
import * as isDev from &#39;electron-is-dev&#39;;
import * as path from &#39;path&#39;;

let mainWindow: BrowserWindow;

const createWindow = () =&gt; {
  mainWindow = new BrowserWindow({
    width: 900,
    height: 680,
    center: true,
    kiosk: !isDev,
    resizable: true,
    fullscreen: false,
    fullscreenable: true,
    webPreferences: {
      // node환경처럼 사용하기
      nodeIntegration: true,
      enableRemoteModule: true,
      // 개발자도구
      devTools: isDev,
    },
  });

  // production에서는 패키지 내부 리소스에 접근.
  // 개발 중에는 개발 도구에서 호스팅하는 주소에서 로드.
  mainWindow.loadURL(isDev ? &#39;http://localhost:3000&#39; : `file://${path.join(__dirname, &#39;../build/index.html&#39;)}`);

  if (isDev) {
    mainWindow.webContents.openDevTools({ mode: &#39;detach&#39; });
  }

  mainWindow.setResizable(true);

  // Emitted when the window is closed.
  mainWindow.on(&#39;closed&#39;, () =&gt; (mainWindow = undefined!));
  mainWindow.focus();
};

// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on(&#39;ready&#39;, createWindow);

// Quit when all windows are closed.
app.on(&#39;window-all-closed&#39;, () =&gt; {
  if (process.platform !== &#39;darwin&#39;) {
    app.quit();
  }
});

app.on(&#39;activate&#39;, () =&gt; {
  if (mainWindow === null) {
    createWindow();
  }
});
</code></pre>
<h1 id="4-packagejson-파일-수정">4. package.json 파일 수정</h1>
<p>프로젝트 파일 내의 <code>package.json</code> 파일을 다음과 같이 수정해준다.</p>
<pre><code class="language-JSON">{
  ...
  &quot;main&quot;: &quot;public/electron.js&quot;,
  &quot;homepage&quot;: &quot;./&quot;,
  &quot;scripts&quot;: {
    &quot;react-start&quot;: &quot;react-scripts start&quot;,
    &quot;react-build&quot;: &quot;react-scripts build&quot;,
    &quot;test&quot;: &quot;react-scripts test&quot;,
    &quot;eject&quot;: &quot;react-scripts eject&quot;,
    &quot;start&quot;: &quot;tsc ./public/electron.ts &amp;&amp; concurrently \&quot;cross-env BROWSER=none npm run react-start\&quot; \&quot;wait-on http://localhost:3000 &amp;&amp; electron .\&quot;&quot;,
    &quot;build&quot;: &quot;npm run react-build &amp;&amp; electron-builder&quot;,
    &quot;release&quot;: &quot;npm run react-build &amp;&amp; electron-builder --publish=always&quot;,
    &quot;lint&quot;: &quot;eslint &#39;./src**/*.{ts,tsx}&#39;&quot;
  },
  ...
}
</code></pre>
<p><strong>main</strong> : 프로그램의 진입점이므로 꼭 설정해주어야함. 일렉트론을 실행하는 코드이다.
<strong>scripts</strong> : </p>
<ul>
<li><strong>[start]</strong> : electron.ts를 js파일로 변환해 준 후, concurrently를 통해 browser로 띄우지 않고 리액트를 실행시킨 후 <a href="http://localhost:3000%EC%9D%B4">http://localhost:3000이</a> 로드가 완료되면 electron을 실행시킨다.</li>
<li><strong>[build]</strong> : <code>dist</code>폴더에 production 실행파일을 생성해준다.</li>
<li><strong>[release]</strong> : build명령어와 같지만 그 후 배포를 해준다. (추가설정 필요)</li>
</ul>
<h1 id="5-실행">5. 실행</h1>
<p><code>npm run start</code>를 터미널에 입력해주면 다음과 같이 앱이 뜨고, 가운데 리액트 마크가 <del>삥글삥글</del> 돈다면 성공적으로 완료되었다.
<img src="https://images.velog.io/images/dev_hikun/post/20a15d05-391b-4cc8-b7e0-be3bce8e1ead/image.png" alt="일렉트론이 실행된 이미지"></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[react 자주겪는 문제 해결방법]]></title>
            <link>https://velog.io/@dev_hikun/react-%EC%9E%90%EC%A3%BC%EA%B2%AA%EB%8A%94-%EB%AC%B8%EC%A0%9C-%ED%95%B4%EA%B2%B0%EB%B0%A9%EB%B2%95</link>
            <guid>https://velog.io/@dev_hikun/react-%EC%9E%90%EC%A3%BC%EA%B2%AA%EB%8A%94-%EB%AC%B8%EC%A0%9C-%ED%95%B4%EA%B2%B0%EB%B0%A9%EB%B2%95</guid>
            <pubDate>Mon, 11 Jan 2021 06:19:48 GMT</pubDate>
            <description><![CDATA[<p>그냥 리액트를 하면서 겪던 린트 에러들 또는 자주 발생했던 에러에 대한 해결방법 모음집 (지속적 업데이트)</p>
<h1 id="1-react-must-be-in-scope-when-using-jsx">1. &#39;React&#39; must be in scope when using JSX</h1>
<pre><code>  import React from &#39;react&#39;</code></pre><p>  위와 같이 임포트해주면 끝. (안해주거나 소문자로 리액트를 임포트 하면 발생하는 에러)</p>
<h1 id="2-ts2322-typescript에서-useref를-사용할-때">2. TS2322: typescript에서 useRef를 사용할 때</h1>
<pre><code class="language-JSON">Type &#39;MutableRefObject&lt;HTMLInputElement | undefined&gt;&#39; is not assignable to type &#39;string | ((instance: HTMLInputElement | null) =&gt; void) | RefObject&lt;HTMLInputElement&gt; | null | undefined&#39;.
  Type &#39;MutableRefObject&lt;HTMLInputElement | undefined&gt;&#39; is not assignable to type &#39;RefObject&lt;HTMLInputElement&gt;&#39;.
    Types of property &#39;current&#39; are incompatible.
      Type &#39;HTMLInputElement | undefined&#39; is not assignable to type &#39;HTMLInputElement | null&#39;.
        Type &#39;undefined&#39; is not assignable to type &#39;HTMLInputElement | null&#39;.  TS2322</code></pre>
<p>  useRef 선언시에 null을 빼트려서 나오는 에러임.</p>
<pre><code>  const abc = useRef&lt;해당하는엘리먼트객체&gt;(null)</code></pre><p>  해주면 끝</p>
]]></description>
        </item>
    </channel>
</rss>