<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>머리가 나뻐서 삽질 SAP(Study And Programming)</title>
    <link>https://serpiko.tistory.com/</link>
    <description>A laziness, the sweet moment leads to a terrible ending. 
나태함, 그 순간은 달콤하나 결과는 비참하다.</description>
    <language>ko</language>
    <pubDate>Tue, 18 Aug 2026 00:14:48 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>serpiko</managingEditor>
    <image>
      <title>머리가 나뻐서 삽질 SAP(Study And Programming)</title>
      <url>https://t1.daumcdn.net/cfile/tistory/2355A15052F5E9A315</url>
      <link>https://serpiko.tistory.com</link>
    </image>
    <item>
      <title>draw.io import (non MCP)</title>
      <link>https://serpiko.tistory.com/913</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;draw.io 에 대한 MCP를 찾고있었는데, claude를 통한 drawio output은 있으나&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;접근및 읽기에 대한 MCP가 없었다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜그런고 하니 이미 mxGraphModel이 충분히 구조화가 잘 되어있는데, 이를 내보내기 하거나&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클립보드로 손쉽게 사용가능하기 때문이라는 답변을 받았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇기에 클립보드로 내보내기 하는 방법을 소개한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;작성된 다이어그램에서&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;663&quot; data-origin-height=&quot;707&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/4xH22/dJMcaftdAcm/YAI7X5ehs3k8kMwVx7cyeK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/4xH22/dJMcaftdAcm/YAI7X5ehs3k8kMwVx7cyeK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/4xH22/dJMcaftdAcm/YAI7X5ehs3k8kMwVx7cyeK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F4xH22%2FdJMcaftdAcm%2FYAI7X5ehs3k8kMwVx7cyeK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;663&quot; height=&quot;707&quot; data-origin-width=&quot;663&quot; data-origin-height=&quot;707&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추가 도구 &amp;gt; 다이어그램 편집&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;236&quot; data-origin-height=&quot;386&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dAHaI8/dJMb990S0Ym/zCgTKwjzlPhES3n5KqUDyk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dAHaI8/dJMb990S0Ym/zCgTKwjzlPhES3n5KqUDyk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dAHaI8/dJMb990S0Ym/zCgTKwjzlPhES3n5KqUDyk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdAHaI8%2FdJMb990S0Ym%2FzCgTKwjzlPhES3n5KqUDyk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;236&quot; height=&quot;386&quot; data-origin-width=&quot;236&quot; data-origin-height=&quot;386&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;출력된 팝업 하단에 &amp;gt; 다이어그램을 클립보드에 복사 를 선택하면 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;602&quot; data-origin-height=&quot;531&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/PsPxS/dJMcagFIuKU/kg5yYoAgWCdd6TbMekpZT1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/PsPxS/dJMcagFIuKU/kg5yYoAgWCdd6TbMekpZT1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/PsPxS/dJMcagFIuKU/kg5yYoAgWCdd6TbMekpZT1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPsPxS%2FdJMcagFIuKU%2Fkg5yYoAgWCdd6TbMekpZT1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;602&quot; height=&quot;531&quot; data-origin-width=&quot;602&quot; data-origin-height=&quot;531&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>AI/MCP</category>
      <category>draw.io clipboard</category>
      <category>drawio clipboard</category>
      <category>drawio XML</category>
      <category>drawio XML내보내기</category>
      <category>drawio 내보내기</category>
      <category>drawio 스키마 내보내기</category>
      <category>drawio 스키마 복사</category>
      <category>drawio 질문하기</category>
      <category>drawio 클립보드</category>
      <category>drawio 클립보드 복사</category>
      <author>serpiko</author>
      <guid isPermaLink="true">https://serpiko.tistory.com/913</guid>
      <comments>https://serpiko.tistory.com/913#entry913comment</comments>
      <pubDate>Thu, 28 May 2026 17:33:20 +0900</pubDate>
    </item>
    <item>
      <title>Figma 무료버전으로 Claude MCP 연결 - Claude Code CLI</title>
      <link>https://serpiko.tistory.com/912</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Figma를 Claude MCP로 연결하고, Claude Desktop으로 운용하는 내용이 있었는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://serpiko.tistory.com/911&quot;&gt;(내용참조 https://serpiko.tistory.com/911&lt;/a&gt;)&lt;/p&gt;
&lt;figure id=&quot;og_1779867341974&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;Figma 무료버전으로 Claude MCP 연결 (with. PAT) - Claude Desktop&quot; data-og-description=&quot;Figma 무료버전으로Claude MCP 연결 (with. PAT) - Claude Desktop유료 플랜 없이 Claude Desktop에서 Figma 파일을 분석하는 가장 현실적인 방법Figma의 공식 Dev Mode MCP Server는 Professional 이상 유료 플랜 + Dev 시트가 &quot; data-og-host=&quot;serpiko.tistory.com&quot; data-og-source-url=&quot;https://serpiko.tistory.com/911&quot; data-og-url=&quot;https://serpiko.tistory.com/911&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/3PfiH/dJMb9b3YvxH/ZPuKuM5PVNVkZyXyATo3N1/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/ezECv/dJMb9eTV2BR/2G1kXmvEBNQn7cYmkJbUx0/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/C16a6/dJMb9kT9qiq/nnNazQhdkk1TXL1jrU1tkk/img.png?width=1276&amp;amp;height=738&amp;amp;face=0_0_1276_738&quot;&gt;&lt;a href=&quot;https://serpiko.tistory.com/911&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://serpiko.tistory.com/911&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/3PfiH/dJMb9b3YvxH/ZPuKuM5PVNVkZyXyATo3N1/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/ezECv/dJMb9eTV2BR/2G1kXmvEBNQn7cYmkJbUx0/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/C16a6/dJMb9kT9qiq/nnNazQhdkk1TXL1jrU1tkk/img.png?width=1276&amp;amp;height=738&amp;amp;face=0_0_1276_738');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Figma 무료버전으로 Claude MCP 연결 (with. PAT) - Claude Desktop&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Figma 무료버전으로Claude MCP 연결 (with. PAT) - Claude Desktop유료 플랜 없이 Claude Desktop에서 Figma 파일을 분석하는 가장 현실적인 방법Figma의 공식 Dev Mode MCP Server는 Professional 이상 유료 플랜 + Dev 시트가&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;serpiko.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번에는 Claude Code CLI 에서 사용하기 위한 방법을 소개하겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;개발환경&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;WSL/Linux&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CLI에서 사용할 때 전역설정을 위해 user (권한 적용 범위는, 아래 표 참조) 범위로 설정하도록 하겠다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;b&gt;값&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;b&gt;효과&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;b&gt;저장 위치&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;user&lt;/td&gt;
&lt;td&gt;모든 프로젝트에서 사용 가능&lt;/td&gt;
&lt;td&gt;~/.claude.json&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;project&lt;/td&gt;
&lt;td&gt;이 프로젝트 + 협업자 공유&lt;/td&gt;
&lt;td&gt;./.mcp.json (git 커밋 가능)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;local (기본)&lt;/td&gt;
&lt;td&gt;이 프로젝트, 본인만&lt;/td&gt;
&lt;td&gt;로컬 settings&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;설정파일 위치 및 추가&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음의 경로에서 설정파일에 mcp를 추가하자&lt;/p&gt;
&lt;pre id=&quot;code_1779867784177&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ cd ~/.claude/json&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1779867878641&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
  &quot;mcpServers&quot;: {
    &quot;figma&quot;: {
      &quot;command&quot;: &quot;npx&quot;,
      &quot;args&quot;: [&quot;-y&quot;, &quot;figma-developer-mcp&quot;, &quot;--stdio&quot;],
      &quot;env&quot;: {
        &quot;FIGMA_API_KEY&quot;: &quot;여기에_PAT_붙여넣기&quot;
      }
    }
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;의 내용을 다음의 위치에 넣으면 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;749&quot; data-origin-height=&quot;322&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/IvHed/dJMcab5pRNb/IsZ3FBjzkfNtKEbj4Vg8kk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/IvHed/dJMcab5pRNb/IsZ3FBjzkfNtKEbj4Vg8kk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/IvHed/dJMcab5pRNb/IsZ3FBjzkfNtKEbj4Vg8kk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIvHed%2FdJMcab5pRNb%2FIsZ3FBjzkfNtKEbj4Vg8kk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;749&quot; height=&quot;322&quot; data-origin-width=&quot;749&quot; data-origin-height=&quot;322&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(Tip: vscode에서는 ctrl+shift+p를 눌러서 WLS에 연결 하면, json 파일을 바로 편하게 열 수 있다)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1138&quot; data-origin-height=&quot;702&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/o6MGY/dJMcaglkVsg/ncKO0iDFcmkd69IWYTNJSk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/o6MGY/dJMcaglkVsg/ncKO0iDFcmkd69IWYTNJSk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/o6MGY/dJMcaglkVsg/ncKO0iDFcmkd69IWYTNJSk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fo6MGY%2FdJMcaglkVsg%2FncKO0iDFcmkd69IWYTNJSk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1138&quot; height=&quot;702&quot; data-origin-width=&quot;1138&quot; data-origin-height=&quot;702&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Claude CLI 로 연결 확인&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;연결 되었음을 확인하기 위해, claude mcp list 명령어로 확인해보자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;888&quot; data-origin-height=&quot;95&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/E7KaW/dJMcacDif2r/diOp61EXE9SriWKloEXOvK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/E7KaW/dJMcacDif2r/diOp61EXE9SriWKloEXOvK/img.png&quot; data-alt=&quot;위와 같이 Connected 가 뜨면 정상 연결&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/E7KaW/dJMcacDif2r/diOp61EXE9SriWKloEXOvK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FE7KaW%2FdJMcacDif2r%2FdiOp61EXE9SriWKloEXOvK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;888&quot; height=&quot;95&quot; data-origin-width=&quot;888&quot; data-origin-height=&quot;95&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;위와 같이 Connected 가 뜨면 정상 연결&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Claude CLI 에서 작업 시작&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;연결이 잘 되었으므로, 본격적으로 피그마와 연결된 자원에 대해 접근이 가능하므로&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;피그마 URL을 알려주고, 컨텍스트가 가능하다!&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;979&quot; data-origin-height=&quot;545&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cuT7lr/dJMcabdnlTv/VIw5t1iKQH7zR2Kn0bksFK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cuT7lr/dJMcabdnlTv/VIw5t1iKQH7zR2Kn0bksFK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cuT7lr/dJMcabdnlTv/VIw5t1iKQH7zR2Kn0bksFK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcuT7lr%2FdJMcabdnlTv%2FVIw5t1iKQH7zR2Kn0bksFK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;979&quot; height=&quot;545&quot; data-origin-width=&quot;979&quot; data-origin-height=&quot;545&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>AI/MCP</category>
      <author>serpiko</author>
      <guid isPermaLink="true">https://serpiko.tistory.com/912</guid>
      <comments>https://serpiko.tistory.com/912#entry912comment</comments>
      <pubDate>Wed, 27 May 2026 16:50:43 +0900</pubDate>
    </item>
    <item>
      <title>Figma 무료버전으로 Claude MCP 연결 (with. PAT) - Claude Desktop</title>
      <link>https://serpiko.tistory.com/911</link>
      <description>&lt;div&gt;
&lt;style&gt;
/* ============================================================
   Tistory 붙여넣기용 — 클래스 접두어 fm- 로 충돌 방지
   본문 영역만 복사하려면 아래 &lt;body&gt; 안쪽 fm-wrap 부터 복사
   ============================================================ */
.fm-wrap{ margin:0; background:#0a0e1f; font-family:'Pretendard',-apple-system,'Apple SD Gothic Neo','Noto Sans KR',sans-serif; }
.fm-wrap{max-width:860px;margin:0 auto;padding:48px 24px 80px;color:#e6e9f2;background:#0a0e1f;line-height:1.65;}
.fm-hero{text-align:center;padding:40px 0 32px;}
.fm-hero h1{font-size:38px;font-weight:900;line-height:1.25;margin:0 0 14px;background:linear-gradient(90deg,#f472b6 0%,#a855f7 45%,#60a5fa 100%);-webkit-background-clip:text;background-clip:text;-webkit-text-fill-color:transparent;letter-spacing:-0.5px;}
.fm-hero p{color:#9ca3b8;font-size:15px;margin:0;}
.fm-intro{background:linear-gradient(135deg,rgba(168,85,247,0.08),rgba(96,165,250,0.05));border:1px solid rgba(168,85,247,0.25);border-radius:14px;padding:22px 24px;margin:24px 0 36px;font-size:14.5px;color:#cdd3e3;}
.fm-intro b{color:#f9a8d4;}
.fm-steps{position:relative;}
.fm-card{display:flex;gap:20px;background:#141a2e;border:1px solid #232a44;border-radius:16px;padding:24px 26px;margin-bottom:18px;position:relative;}
.fm-card::after{content:'';position:absolute;left:46px;bottom:-19px;width:2px;height:18px;background:linear-gradient(180deg,#a855f7,transparent);}
.fm-card:last-child::after{display:none;}
.fm-num{flex-shrink:0;width:48px;height:48px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-weight:800;font-size:18px;color:#fff;background:linear-gradient(135deg,#a855f7,#ec4899);box-shadow:0 0 20px rgba(168,85,247,0.4);}
.fm-body{flex:1;min-width:0;}
.fm-title{font-size:18px;font-weight:700;color:#fff;margin:0 0 8px;display:flex;align-items:center;gap:10px;}
.fm-desc{font-size:14.5px;color:#b5bbcf;margin:0 0 14px;}
.fm-tags{display:flex;flex-wrap:wrap;gap:7px;margin-bottom:0;}
.fm-tag{display:inline-block;padding:5px 11px;border-radius:999px;font-size:12px;font-weight:600;letter-spacing:-0.2px;}
.fm-tag-purple{background:rgba(168,85,247,0.15);color:#c084fc;}
.fm-tag-pink{background:rgba(236,72,153,0.15);color:#f472b6;}
.fm-tag-blue{background:rgba(96,165,250,0.15);color:#93c5fd;}
.fm-tag-green{background:rgba(52,211,153,0.15);color:#6ee7b7;}
.fm-tag-orange{background:rgba(251,146,60,0.15);color:#fdba74;}
.fm-code{background:#0d1224;border:1px solid #232a44;border-radius:10px;padding:14px 16px;margin:14px 0 0;font-family:'JetBrains Mono','Consolas',monospace;font-size:13px;color:#cdd3e3;overflow-x:auto;white-space:pre;line-height:1.55;}
.fm-code .k{color:#f472b6;}
.fm-code .s{color:#86efac;}
.fm-code .c{color:#6b7280;font-style:italic;}
.fm-code .n{color:#fbbf24;}
.fm-figure{margin:16px 0 0;background:#0d1224;border:1px dashed #3b4366;border-radius:10px;padding:14px;text-align:center;}
.fm-figure img{max-width:100%;height:auto;border-radius:8px;display:block;margin:0 auto;}
.fm-figure figcaption{font-size:12.5px;color:#8b91a8;margin-top:10px;font-style:italic;}
.fm-flow{margin:14px 0 0;}
.fm-flow-step{background:#0d1224;border-left:3px solid #a855f7;padding:10px 14px;margin-bottom:8px;border-radius:6px;font-size:13.5px;color:#cdd3e3;}
.fm-flow-arrow{text-align:center;color:#a855f7;font-size:18px;line-height:1;margin:-2px 0;}
.fm-callout{background:rgba(251,191,36,0.08);border:1px solid rgba(251,191,36,0.3);border-radius:10px;padding:12px 16px;margin:14px 0 0;font-size:13.5px;color:#fde68a;}
.fm-callout b{color:#fcd34d;}
.fm-outro{text-align:center;margin-top:48px;padding:32px 24px;background:linear-gradient(135deg,rgba(168,85,247,0.1),rgba(96,165,250,0.06));border:1px solid rgba(168,85,247,0.25);border-radius:16px;}
.fm-outro h2{font-size:22px;background:linear-gradient(90deg,#f472b6,#a855f7,#60a5fa);-webkit-background-clip:text;background-clip:text;-webkit-text-fill-color:transparent;margin:0 0 12px;font-weight:800;}
.fm-outro p{color:#cdd3e3;font-size:14.5px;margin:0;}
@media (max-width:600px){
  .fm-hero h1{font-size:28px;}
  .fm-card{padding:20px;gap:14px;}
  .fm-num{width:40px;height:40px;font-size:16px;}
  .fm-card::after{left:38px;}
}
&lt;/style&gt;
&lt;/div&gt;
&lt;!-- ============ 여기서부터 Tistory에 복사 ============ --&gt;
&lt;div class=&quot;fm-wrap&quot;&gt;&lt;header class=&quot;fm-hero&quot;&gt;
&lt;h1&gt;Figma 무료버전으로&lt;br /&gt;Claude MCP 연결 (with. PAT) - Claude Desktop&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유료 플랜 없이 Claude Desktop에서 Figma 파일을 분석하는 가장 현실적인 방법&lt;/p&gt;
&lt;/header&gt;
&lt;div class=&quot;fm-intro&quot;&gt;Figma의 공식 Dev Mode MCP Server는 &lt;b&gt;Professional 이상 유료 플랜 + Dev 시트&lt;/b&gt;가 필요하다.&lt;br /&gt;&lt;br /&gt;그래서 무료 계정에서는 안되지만 &lt;b&gt;커뮤니티 MCP(&lt;code&gt;figma-developer-mcp&lt;/code&gt;) + Personal Access Token(PAT)&lt;/b&gt; 조합으로&lt;br /&gt;Claude MCP로 연결이 가능하다.&lt;br /&gt;&lt;br /&gt;참고로 기획서를 같이 살펴보고, 논의를 진행하기 위해서 Claude CLI가 아닌 Windows Claude Desktop 으로 진행하였다.&lt;br /&gt;&lt;br /&gt;본 내용은 연결까지 성공한 전 과정을 단계별로 정리한 가이드이다.&lt;/div&gt;
&lt;section class=&quot;fm-steps&quot;&gt;&lt;!-- STEP 1 --&gt;
&lt;div class=&quot;fm-card&quot;&gt;
&lt;div class=&quot;fm-num&quot;&gt;1&lt;/div&gt;
&lt;div class=&quot;fm-body&quot;&gt;
&lt;h3 class=&quot;fm-title&quot; data-ke-size=&quot;size23&quot;&gt;  개발환경 &amp;mdash; Windows&lt;/h3&gt;
&lt;p class=&quot;fm-desc&quot; data-ke-size=&quot;size16&quot;&gt;Claude Desktop은 Windows 프로세스로 실행되므로 MCP 서버 실행에 필요한 도구들도 Windows 측에 설치되어 있어야 한다. (참고로 WSL에 Node.js가 있어도 Claude Desktop은 이것을 직접 사용하지 못하므로 연관성이 없다.)&lt;/p&gt;
&lt;div class=&quot;fm-tags&quot;&gt;&lt;span class=&quot;fm-tag fm-tag-blue&quot;&gt;Windows 11/10&lt;/span&gt; &lt;span class=&quot;fm-tag fm-tag-purple&quot;&gt;Claude Desktop&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;!-- STEP 2 --&gt;
&lt;div class=&quot;fm-card&quot;&gt;
&lt;div class=&quot;fm-num&quot;&gt;2&lt;/div&gt;
&lt;div class=&quot;fm-body&quot;&gt;
&lt;h3 class=&quot;fm-title&quot; data-ke-size=&quot;size23&quot;&gt;  Node.js &amp;middot; npm 버전 확인&lt;/h3&gt;
&lt;p class=&quot;fm-desc&quot; data-ke-size=&quot;size16&quot;&gt;먼저 Windows 에 nodejs를 설치하자, &lt;a style=&quot;color: #93c5fd;&quot; href=&quot;https://nodejs.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;nodejs.org&lt;/a&gt;에서 LTS 버전을 설치한 뒤 PowerShell에서 버전을 확인하면 된다. &lt;br /&gt;&lt;code&gt;npx&lt;/code&gt;는 Node.js에 포함되어 있기 때문에 별도 설치는 필요없다.&lt;/p&gt;
&lt;div class=&quot;fm-code&quot;&gt;&lt;span class=&quot;c&quot;&gt;# PowerShell&lt;/span&gt; &lt;br /&gt;&lt;span class=&quot;k&quot;&gt;PS&lt;/span&gt; C:\Users\User&amp;gt; node -v &lt;br /&gt;&lt;span class=&quot;n&quot;&gt;v24.16.0&lt;/span&gt; &lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;k&quot;&gt;PS&lt;/span&gt; C:\Users\User&amp;gt; npm -v &lt;br /&gt;&lt;span class=&quot;n&quot;&gt;11.13.0&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;fm-tags&quot; style=&quot;margin-top: 14px;&quot;&gt;&lt;span class=&quot;fm-tag fm-tag-green&quot;&gt;Node v24.16.0&lt;/span&gt; &lt;span class=&quot;fm-tag fm-tag-green&quot;&gt;npm 11.13.0&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;!-- STEP 3 --&gt;
&lt;div class=&quot;fm-card&quot;&gt;
&lt;div class=&quot;fm-num&quot;&gt;3&lt;/div&gt;
&lt;div class=&quot;fm-body&quot;&gt;
&lt;h3 class=&quot;fm-title&quot; data-ke-size=&quot;size23&quot;&gt;⚠️ 트러블슈팅 &amp;mdash; PowerShell 실행 정책&lt;/h3&gt;
&lt;p class=&quot;fm-desc&quot; data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;npm -v&lt;/code&gt; 실행 시 `&lt;b&gt;npm: 이 시스템에서 스크립트를 실행할 수 없으므로...` &lt;/b&gt;오류가 나는 경우가 있다. &lt;br /&gt;Windows의 기본 ExecutionPolicy가 &lt;code&gt;Restricted&lt;/code&gt;여서 발생하는 보안 차단인데, 현재 사용자 범위에서만 &lt;br /&gt;풀어주면 안전하게 해결된다.&lt;/p&gt;
&lt;div class=&quot;fm-code&quot;&gt;&lt;span class=&quot;c&quot;&gt;# 현재 사용자에 대해서만 서명된 원격 스크립트 허용&lt;/span&gt; &lt;br /&gt;&lt;span class=&quot;k&quot;&gt;PS&lt;/span&gt; C:\Users\User&amp;gt; Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned &lt;span class=&quot;c&quot;&gt;# 이후 npm 정상 동작&lt;/span&gt; &lt;br /&gt;&lt;span class=&quot;k&quot;&gt;PS&lt;/span&gt; C:\Users\User&amp;gt; npm -v &lt;span class=&quot;n&quot;&gt;11.13.0&lt;/span&gt;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div class=&quot;fm-tags&quot; style=&quot;margin-top: 14px;&quot;&gt;&lt;span class=&quot;fm-tag fm-tag-orange&quot;&gt;PSSecurityException&lt;/span&gt; &lt;span class=&quot;fm-tag fm-tag-purple&quot;&gt;RemoteSigned&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;!-- STEP 4 --&gt;
&lt;div class=&quot;fm-card&quot;&gt;
&lt;div class=&quot;fm-num&quot;&gt;4&lt;/div&gt;
&lt;div class=&quot;fm-body&quot;&gt;
&lt;h3 class=&quot;fm-title&quot; data-ke-size=&quot;size23&quot;&gt;  Figma에서 PAT 발급&lt;/h3&gt;
&lt;p class=&quot;fm-desc&quot; data-ke-size=&quot;size16&quot;&gt;Figma &lt;b&gt;Settings&lt;/b&gt; &amp;rarr; &lt;b&gt;Security&lt;/b&gt; &amp;rarr; &lt;b&gt;Personal access tokens&lt;/b&gt; &amp;rarr; &lt;code&gt;Generate new token&lt;/code&gt;&amp;nbsp;&lt;br /&gt;무료(Starter) 계정도 PAT 발급이 가능하다. &lt;br /&gt;토큰 이름은 식별하기 좋게(예: &lt;code&gt;Claude-Figma-MCP&lt;/code&gt;), 권한은 &lt;b&gt;Read 계열&lt;/b&gt;에 체크하면 충분하고, 생성 시 &lt;br /&gt;한 번만 보이는 토큰을 반드시 저장해 놓아야 한다.&lt;/p&gt;
&lt;p class=&quot;fm-desc&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div class=&quot;fm-callout&quot;&gt;&lt;b&gt;⚠️ 보안:&lt;/b&gt; PAT는 비밀번호와 같다. 채팅&amp;middot;블로그&amp;middot;캡처에 절대 노출하지 안된다. &lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;노출되면 즉시 Revoke 후 재발급해야 하며, 만료기간(90일 권장)을 짧게 잡으면 더 안전하다.&lt;/div&gt;
&lt;div class=&quot;fm-tags&quot; style=&quot;margin-top: 14px;&quot;&gt;&lt;span class=&quot;fm-tag fm-tag-pink&quot;&gt;무료 계정 OK&lt;/span&gt; &lt;span class=&quot;fm-tag fm-tag-blue&quot;&gt;Read 권한&lt;/span&gt; &lt;span class=&quot;fm-tag fm-tag-orange&quot;&gt;노출 금지&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;!-- STEP 5 --&gt;
&lt;div class=&quot;fm-card&quot;&gt;
&lt;div class=&quot;fm-num&quot;&gt;5&lt;/div&gt;
&lt;div class=&quot;fm-body&quot;&gt;
&lt;h3 class=&quot;fm-title&quot; data-ke-size=&quot;size23&quot;&gt;  Claude Desktop 실행 &amp;middot; 설정 진입&lt;/h3&gt;
&lt;p class=&quot;fm-desc&quot; data-ke-size=&quot;size16&quot;&gt;Claude Desktop 좌측 상단 &lt;b&gt;File &amp;rarr; Settings&lt;/b&gt; (또는&lt;/p&gt;
&lt;kbd&gt;Ctrl + ,&lt;/kbd&gt;
&lt;p class=&quot;fm-desc&quot; data-ke-size=&quot;size16&quot;&gt;) &amp;rarr; 좌측 탭 &lt;b&gt;개발자(Developer)&lt;/b&gt; &amp;rarr; &lt;b&gt;구성 편집(Edit Config)&lt;/b&gt; 버튼을 클릭하면 &lt;code&gt;claude_desktop_config.json&lt;/code&gt; 파일 위치로 탐색기가 열린다.&lt;/p&gt;
&lt;div class=&quot;fm-code&quot;&gt;파일 위치: %APPDATA%\Claude\claude_desktop_config.json &lt;br /&gt;실제 경로: C:\Users\&amp;lt;사용자명&amp;gt;\AppData\Roaming\Claude\claude_desktop_config.json&lt;/div&gt;
&lt;div class=&quot;fm-tags&quot; style=&quot;margin-top: 14px;&quot;&gt;&lt;span class=&quot;fm-tag fm-tag-purple&quot;&gt;Developer 탭&lt;/span&gt; &lt;span class=&quot;fm-tag fm-tag-blue&quot;&gt;JSON 편집&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;!-- STEP 6 --&gt;
&lt;div class=&quot;fm-card&quot;&gt;
&lt;div class=&quot;fm-num&quot;&gt;6&lt;/div&gt;
&lt;div class=&quot;fm-body&quot;&gt;
&lt;h3 class=&quot;fm-title&quot; data-ke-size=&quot;size23&quot;&gt;⚙️ claude_desktop_config.json 편집&lt;/h3&gt;
&lt;p class=&quot;fm-desc&quot; data-ke-size=&quot;size16&quot;&gt;최상위에 &lt;code&gt;mcpServers&lt;/code&gt; 키를 추가하고, 그 안에 &lt;code&gt;figma&lt;/code&gt; 서버 항목을 정의한다. &lt;br /&gt;Windows에서 &lt;code&gt;npx&lt;/code&gt;를 안정적으로 실행하기 위해 &lt;code&gt;cmd /c&lt;/code&gt; 래핑을 사용한 것이 포인트이다.&lt;/p&gt;
&lt;div class=&quot;fm-code&quot;&gt;{ &lt;span class=&quot;k&quot;&gt;&quot;preferences&quot;&lt;/span&gt;: { &lt;br /&gt;&lt;span class=&quot;c&quot;&gt; // 기존 환경설정들 그대로 유지&lt;/span&gt; &lt;br /&gt;&lt;span class=&quot;k&quot;&gt; &quot;menuBarEnabled&quot;&lt;/span&gt;: &lt;span class=&quot;n&quot;&gt;false&lt;/span&gt;, &lt;br /&gt;&lt;span class=&quot;k&quot;&gt; &quot;sidebarMode&quot;&lt;/span&gt;: &lt;span class=&quot;s&quot;&gt;&quot;task&quot;&lt;/span&gt;, &lt;br /&gt;&lt;span class=&quot;k&quot;&gt; &quot;bypassPermissionsGateByAccount&quot;&lt;/span&gt;: { &lt;br /&gt;&lt;span class=&quot;k&quot;&gt; &quot;&amp;lt;your-account-uuid&amp;gt;&quot;&lt;/span&gt;: &lt;span class=&quot;n&quot;&gt;false&lt;/span&gt; &lt;br /&gt;}, &lt;br /&gt;&lt;span class=&quot;k&quot;&gt; &quot;remoteToolsDeviceName&quot;&lt;/span&gt;: &lt;span class=&quot;s&quot;&gt;&quot;&amp;lt;your-device-name&amp;gt;&quot;&lt;/span&gt; &lt;br /&gt;&lt;span class=&quot;c&quot;&gt; // ... 그 외 prefs&lt;/span&gt; &lt;br /&gt;}, &lt;br /&gt;&lt;span class=&quot;k&quot;&gt;&quot;mcpServers&quot;&lt;/span&gt;: { &lt;br /&gt;&lt;span class=&quot;k&quot;&gt; &quot;figma&quot;&lt;/span&gt;: { &lt;br /&gt;&lt;span class=&quot;k&quot;&gt; &quot;command&quot;&lt;/span&gt;: &lt;span class=&quot;s&quot;&gt;&quot;cmd&quot;&lt;/span&gt;, &lt;br /&gt;&lt;span class=&quot;k&quot;&gt; &quot;args&quot;&lt;/span&gt;: [&lt;span class=&quot;s&quot;&gt;&quot;/c&quot;&lt;/span&gt;, &lt;span class=&quot;s&quot;&gt;&quot;npx&quot;&lt;/span&gt;, &lt;span class=&quot;s&quot;&gt;&quot;-y&quot;&lt;/span&gt;, &lt;span class=&quot;s&quot;&gt;&quot;figma-developer-mcp&quot;&lt;/span&gt;, &lt;span class=&quot;s&quot;&gt;&quot;--stdio&quot;&lt;/span&gt;], &lt;br /&gt;&lt;span class=&quot;k&quot;&gt; &quot;env&quot;&lt;/span&gt;: { &lt;br /&gt;&lt;span class=&quot;k&quot;&gt; &quot;FIGMA_API_KEY&quot;&lt;/span&gt;: &lt;span class=&quot;s&quot;&gt;&quot;여기에_PAT_붙여넣기&quot;&lt;/span&gt; &lt;br /&gt;} &lt;br /&gt;} &lt;br /&gt;} &lt;br /&gt;}&lt;/div&gt;
&lt;div class=&quot;fm-callout&quot;&gt;&lt;b&gt;  핵심 체크포인트 &amp;mdash; 이름은 소문자 &lt;code&gt;figma&lt;/code&gt;로!&lt;/b&gt;&lt;br /&gt;Claude Desktop에는 Anthropic이 기본 제공하는 &lt;code&gt;Figma&lt;/code&gt;(대문자) Extension이 있다. &lt;br /&gt;우리는 추가하는 커뮤니티 MCP는 이름 충돌을 피하려고 &lt;b&gt;소문자 figma&lt;/b&gt;로 등록했다. &lt;br /&gt;이 둘은 별개 서버로 공존한다.&lt;/div&gt;
&lt;div class=&quot;fm-tags&quot; style=&quot;margin-top: 14px;&quot;&gt;&lt;span class=&quot;fm-tag fm-tag-purple&quot;&gt;mcpServers 추가&lt;/span&gt; &lt;span class=&quot;fm-tag fm-tag-pink&quot;&gt;소문자 figma&lt;/span&gt; &lt;span class=&quot;fm-tag fm-tag-blue&quot;&gt;cmd /c 래핑&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;!-- STEP 7 --&gt;
&lt;div class=&quot;fm-card&quot;&gt;
&lt;div class=&quot;fm-num&quot;&gt;7&lt;/div&gt;
&lt;div class=&quot;fm-body&quot;&gt;
&lt;h3 class=&quot;fm-title&quot; data-ke-size=&quot;size23&quot;&gt;✅ MCP 서버 연결 확인&lt;/h3&gt;
&lt;p class=&quot;fm-desc&quot; data-ke-size=&quot;size16&quot;&gt;파일 저장 후 Claude Desktop을 &lt;b&gt;완전 종료(트레이 아이콘까지 종료)&lt;/b&gt; &amp;rarr; 재시작 Settings &amp;rarr; Developer &amp;rarr; 로컬 MCP 서버 화면에서 &lt;code&gt;figma&lt;/code&gt;(소문자) 항목이 &lt;b&gt;running&lt;/b&gt; 상태로 떠 있으면 성공.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;b&gt;핵심 포인트 (중요)&lt;/b&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1261&quot; data-origin-height=&quot;601&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cjCzwZ/dJMcac4idgv/nLFlXGqM93AUAkcAeHfuU0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cjCzwZ/dJMcac4idgv/nLFlXGqM93AUAkcAeHfuU0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cjCzwZ/dJMcac4idgv/nLFlXGqM93AUAkcAeHfuU0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcjCzwZ%2FdJMcac4idgv%2FnLFlXGqM93AUAkcAeHfuU0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1261&quot; height=&quot;601&quot; data-origin-width=&quot;1261&quot; data-origin-height=&quot;601&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1281&quot; data-origin-height=&quot;601&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cJVZFr/dJMcabddNDW/JqKtJPtn6iPSEm3Sg0NNSK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cJVZFr/dJMcabddNDW/JqKtJPtn6iPSEm3Sg0NNSK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cJVZFr/dJMcabddNDW/JqKtJPtn6iPSEm3Sg0NNSK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcJVZFr%2FdJMcabddNDW%2FJqKtJPtn6iPSEm3Sg0NNSK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1281&quot; height=&quot;601&quot; data-origin-width=&quot;1281&quot; data-origin-height=&quot;601&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1276&quot; data-origin-height=&quot;738&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bDWjMI/dJMcajbcAr4/1kX07oG3K0EW12y5XRJlik/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bDWjMI/dJMcajbcAr4/1kX07oG3K0EW12y5XRJlik/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bDWjMI/dJMcajbcAr4/1kX07oG3K0EW12y5XRJlik/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbDWjMI%2FdJMcajbcAr4%2F1kX07oG3K0EW12y5XRJlik%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1276&quot; height=&quot;738&quot; data-origin-width=&quot;1276&quot; data-origin-height=&quot;738&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div class=&quot;fm-tags&quot; style=&quot;margin-top: 14px;&quot;&gt;&lt;span class=&quot;fm-tag fm-tag-green&quot;&gt;running&lt;/span&gt; &lt;span class=&quot;fm-tag fm-tag-purple&quot;&gt;대소문자 구분&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;!-- STEP 8 --&gt;
&lt;div class=&quot;fm-card&quot;&gt;
&lt;div class=&quot;fm-num&quot;&gt;8&lt;/div&gt;
&lt;div class=&quot;fm-body&quot;&gt;
&lt;h3 class=&quot;fm-title&quot; data-ke-size=&quot;size23&quot;&gt;  내부 동작 흐름 (자동으로 일어나는 일)&lt;/h3&gt;
&lt;p class=&quot;fm-desc&quot; data-ke-size=&quot;size16&quot;&gt;설정 저장과 재시작만 했을 뿐인데 어떻게 연결되는 걸까? 백그라운드에서 다음 흐름이 자동으로 일어나게 된다.&lt;/p&gt;
&lt;div class=&quot;fm-flow&quot;&gt;
&lt;div class=&quot;fm-flow-step&quot;&gt;  &lt;b&gt;Claude Desktop 시작&lt;/b&gt; &amp;mdash; claude_desktop_config.json 읽음&lt;/div&gt;
&lt;div class=&quot;fm-flow-arrow&quot;&gt;&amp;darr;&lt;/div&gt;
&lt;div class=&quot;fm-flow-step&quot;&gt;⚡ &lt;b&gt;&quot;cmd /c npx -y figma-developer-mcp --stdio&quot;&lt;/b&gt; 명령 실행&lt;/div&gt;
&lt;div class=&quot;fm-flow-arrow&quot;&gt;&amp;darr;&lt;/div&gt;
&lt;div class=&quot;fm-flow-step&quot;&gt;  &lt;b&gt;npx가 figma-developer-mcp 패키지 자동 다운로드&lt;/b&gt; (최초 1회, 10~30초 소요)&lt;/div&gt;
&lt;div class=&quot;fm-flow-arrow&quot;&gt;&amp;darr;&lt;/div&gt;
&lt;div class=&quot;fm-flow-step&quot;&gt; ️ &lt;b&gt;MCP 서버 프로세스 백그라운드 실행&lt;/b&gt;&lt;/div&gt;
&lt;div class=&quot;fm-flow-arrow&quot;&gt;&amp;darr;&lt;/div&gt;
&lt;div class=&quot;fm-flow-step&quot;&gt;  &lt;b&gt;PAT로 Figma REST API 인증&lt;/b&gt;&lt;/div&gt;
&lt;div class=&quot;fm-flow-arrow&quot;&gt;&amp;darr;&lt;/div&gt;
&lt;div class=&quot;fm-flow-step&quot;&gt;  &lt;b&gt;Claude Desktop &amp;harr; MCP 서버 stdio 통신 시작&lt;/b&gt;&lt;/div&gt;
&lt;div class=&quot;fm-flow-arrow&quot;&gt;&amp;darr;&lt;/div&gt;
&lt;div class=&quot;fm-flow-step&quot;&gt;  &lt;b&gt;연결 완료 &amp;mdash; 채팅에서 Figma 도구 사용 가능&lt;/b&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;fm-tags&quot; style=&quot;margin-top: 14px;&quot;&gt;&lt;span class=&quot;fm-tag fm-tag-blue&quot;&gt;stdio 통신&lt;/span&gt; &lt;span class=&quot;fm-tag fm-tag-purple&quot;&gt;REST API 인증&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;!-- STEP 9 --&gt;
&lt;div class=&quot;fm-card&quot;&gt;
&lt;div class=&quot;fm-num&quot;&gt;9&lt;/div&gt;
&lt;div class=&quot;fm-body&quot;&gt;
&lt;h3 class=&quot;fm-title&quot; data-ke-size=&quot;size23&quot;&gt;  실제 호출 테스트 &amp;mdash; Figma URL 분석&lt;/h3&gt;
&lt;p class=&quot;fm-desc&quot; data-ke-size=&quot;size16&quot;&gt;Figma 파일 URL을 복사해 Claude에게 &quot;이 파일의 메타데이터 간단히 요약해줘&quot; 라고 요청하면, MCP가 자동으로 호출되어 페이지&amp;middot;프레임&amp;middot;컴포넌트 구조를 분석해준다. 테스트용으로 Figma 공식 튜토리얼 Figma basics 파일을 사용했다.&lt;/p&gt;
&lt;p class=&quot;fm-desc&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;fm-desc&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div class=&quot;fm-callout&quot;&gt;&lt;b&gt;  토큰 절약 팁:&lt;/b&gt; 큰 파일은 전체 호출 시 응답이 매우 커집니다. 특정 페이지/프레임의 &lt;code&gt;node-id&lt;/code&gt;를 지정해 부분만 호출하거나, &quot;메타데이터만&quot; 같은 가벼운 요청으로 시작하세요.&lt;/div&gt;
&lt;div class=&quot;fm-tags&quot; style=&quot;margin-top: 14px;&quot;&gt;&lt;span class=&quot;fm-tag fm-tag-green&quot;&gt;실전 테스트&lt;/span&gt; &lt;span class=&quot;fm-tag fm-tag-pink&quot;&gt;분석 성공&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;position: absolute;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div class=&quot;fm-outro&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  연결 완료 &amp;mdash; 이제 무료로 Figma &amp;times; Claude&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유료 시트 없이도 PAT 한 줄로 Figma 파일을 Claude와 함께 분석할 수 있게 됐다.&lt;br /&gt;대규모 파일은 부분 호출, PAT는 정기 교체 &amp;mdash; 두 가지만 기억하면 안전하고 효율적으로 쓸 수 있게되었다!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;!-- ============ 여기까지가 Tistory 복사 영역 ============ --&gt;</description>
      <category>AI/MCP</category>
      <author>serpiko</author>
      <guid isPermaLink="true">https://serpiko.tistory.com/911</guid>
      <comments>https://serpiko.tistory.com/911#entry911comment</comments>
      <pubDate>Tue, 26 May 2026 17:50:24 +0900</pubDate>
    </item>
    <item>
      <title>grafana in react</title>
      <link>https://serpiko.tistory.com/907</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;그라파나 대시보드를 리액트에 바로 표시할 수 있도록 해보자&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테스트 준비물&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 그라파나 대시보드의 Public dashboard (admin 권한 필요)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 프록시 서버&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 리액트 CRA&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;1.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;그라파나 대시보드의 Public dashboard (admin 권한 필요)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1-1) &lt;a href=&quot;https://grafana.com/docs/grafana/latest/dashboards/dashboard-public/#public-dashboards&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Public dashbaord&lt;/a&gt; 란&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 누구나 접근할 수 있도록 설정된 대시보드&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 기본적으로 Grafana 대시보드는 인증을 요구하지만, 대시보드 공개 설정하면 인증 없이 접근할 수 있다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1-2) Public Dashboard 설정 방법&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 다음과 같이 대시보드를 통째로 가져올 수 있다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp;- 일일이 그래프 하나씩 가져오는 것 보다, 그라파나 대시보드에 필요한 모니터링 자원을 셋팅해서 &lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; 그 대시보드를 전부 가져오는게 더 효율적이다&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1247&quot; data-origin-height=&quot;632&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bE1nUX/btsLCpfSbSL/LcGvII9DwTbi6m8QfUVDTk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bE1nUX/btsLCpfSbSL/LcGvII9DwTbi6m8QfUVDTk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bE1nUX/btsLCpfSbSL/LcGvII9DwTbi6m8QfUVDTk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbE1nUX%2FbtsLCpfSbSL%2FLcGvII9DwTbi6m8QfUVDTk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1247&quot; height=&quot;632&quot; data-origin-width=&quot;1247&quot; data-origin-height=&quot;632&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 대시보드 그래프 하나를 선택해서 오른쪽 상단의 Share 버튼을 클릭한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1063&quot; data-origin-height=&quot;388&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/buZ9uH/btsLBvtN9K3/u6OW0pZ4mwMzp4gnUaP6tK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/buZ9uH/btsLBvtN9K3/u6OW0pZ4mwMzp4gnUaP6tK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/buZ9uH/btsLBvtN9K3/u6OW0pZ4mwMzp4gnUaP6tK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbuZ9uH%2FbtsLBvtN9K3%2Fu6OW0pZ4mwMzp4gnUaP6tK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1063&quot; height=&quot;388&quot; data-origin-width=&quot;1063&quot; data-origin-height=&quot;388&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 중간 부분에 노출과 관련된 옵션이 있는데 (참고를 위한 아래의 이미지는, 관리자 권한에서 이미 대시보드로의 노출이 되었기 때문에, 별다른 옵션이 보이지 않고 공개 해제 토글버튼으로 존재하고 있는 모습이다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp;이 옵션을 모두 활성화 한 뒤, 확인을 누른다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp;- 참고로 옵션은 모두 공개할 지, 특정 역할에 대해 공개할 지 등의 권한이 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;945&quot; data-origin-height=&quot;517&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pNVOr/btsLDcz7UVl/7q3JnluPfIPZKouJks9IMK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pNVOr/btsLDcz7UVl/7q3JnluPfIPZKouJks9IMK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pNVOr/btsLDcz7UVl/7q3JnluPfIPZKouJks9IMK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpNVOr%2FbtsLDcz7UVl%2F7q3JnluPfIPZKouJks9IMK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;945&quot; height=&quot;517&quot; data-origin-width=&quot;945&quot; data-origin-height=&quot;517&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 대시보드 url을 복사하거나, 확인한다&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;903&quot; data-origin-height=&quot;85&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nCS3Q/btsLC5uaRCq/gAaJUSbK8kSiNZjL8PHbyk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nCS3Q/btsLC5uaRCq/gAaJUSbK8kSiNZjL8PHbyk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nCS3Q/btsLC5uaRCq/gAaJUSbK8kSiNZjL8PHbyk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnCS3Q%2FbtsLC5uaRCq%2FgAaJUSbK8kSiNZjL8PHbyk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;903&quot; height=&quot;85&quot; data-origin-width=&quot;903&quot; data-origin-height=&quot;85&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 프록시 서버&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2-1) CORS의 처리가 필요하다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2-2) 호출 서버에서 X-Frame-Optiopns 헤더가 DENY로 설정되어있으면 안된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;DENY로 설정되어 있으면, iframe으로 불러오는 것을 차단하기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프록시 서버는 아주 간략한 스크립트로 nodejs 의 express를 이용하여 구축하였다, git 레포지토리의 도움을 받는 경우 &lt;a href=&quot;https://github.com/serpiko-git/react-proxy-tutorial/blob/main/src/proxy.js&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;여기&lt;/a&gt;를 참조하되&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제 내용물은 아래에 있는 proxy.js 를 사용해야 한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;package.json&lt;/p&gt;
&lt;pre id=&quot;code_1735796486967&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
  &quot;name&quot;: &quot;proxy&quot;,
  &quot;version&quot;: &quot;0.1.0&quot;,
  &quot;description&quot;: &quot;Sample implementation of proxy&quot;,
  &quot;type&quot;: &quot;module&quot;,
  &quot;main&quot;: &quot;index.js&quot;,
  &quot;dependencies&quot;: {
    &quot;cors&quot;: &quot;^2.8.4&quot;,
    &quot;express&quot;: &quot;^4.16.3&quot;,
    &quot;express-http-proxy&quot;: &quot;^1.2.0&quot;,
    &quot;morgan&quot;: &quot;^1.9.0&quot;
  },
  &quot;devDependencies&quot;: {},
  &quot;scripts&quot;: {
    &quot;proxy&quot;: &quot;node proxy.js&quot;,
    &quot;proxy:ts&quot;: &quot;ts-node proxy.ts&quot;,
    &quot;serve&quot;: &quot;http-server ./index.html -p 8080 -c-1&quot;
  },
  &quot;author&quot;: &quot;serpiko&quot;,
  &quot;license&quot;: &quot;MIT&quot;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;proxy.js&lt;/p&gt;
&lt;pre id=&quot;code_1735796408614&quot; class=&quot;javascript&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;import cors from &quot;cors&quot;;
import express from &quot;express&quot;;
import proxy from &quot;express-http-proxy&quot;;
import morgan from &quot;morgan&quot;;

const app = express();
app.use(cors());

app.use(morgan(&quot;tiny&quot;));

app.use(
  &quot;/&quot;,
  proxy(&quot;http://my-grafana-domain:3006&quot;, {
    userResHeaderDecorator(headers) {
      delete headers[&quot;x-frame-options&quot;]; // X-Frame-Options 헤더 제거
      return headers;
    },
  })
);

app.listen(20090, () =&amp;gt; {
  console.log(&quot;  Listening on 20090,   Proxy [ http://my-grafana-domain:3006 ]&quot;);
});&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;프록시 서버 구동은 다음과 같이&lt;/p&gt;
&lt;pre id=&quot;code_1735796578738&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ npm run proxy&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프록시 실행결과&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;544&quot; data-origin-height=&quot;126&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mZKnu/btsLBl518yo/jF66scGrbzVhuN8sRXjfe1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mZKnu/btsLBl518yo/jF66scGrbzVhuN8sRXjfe1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mZKnu/btsLBl518yo/jF66scGrbzVhuN8sRXjfe1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmZKnu%2FbtsLBl518yo%2FjF66scGrbzVhuN8sRXjfe1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;544&quot; height=&quot;126&quot; data-origin-width=&quot;544&quot; data-origin-height=&quot;126&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 리액트 CRA&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 가장 빠르게 확인하기 위해서 리액트 타입스크립트 없이, CRA를 이용하였다.&lt;/p&gt;
&lt;pre id=&quot;code_1735796648124&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ npx create-react-app grafana-in-cra&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 이후 그라파나 컴포넌트를 한 개 만들어서, 아까 1번 에서 설정한 URL을 사용하자&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Grafana.js&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- URL은 우리가 프록시로 띄운 서버 호스트 (http://localhost:20090) 에 나머지 기존 URL을 연결하도록 한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 예를 들면 origin URL을 =&amp;gt; Proxy URL로 사용해야 하므로, 다음과 같다&lt;/p&gt;
&lt;pre id=&quot;code_1735797393511&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// origin URL
http://my-grafana-domain/public-dashboards/ef18a1c1b4e74dd8ae09387b86fe16b6?orgId=1&amp;amp;refresh=5s

// Proxy URL
http://localhost:20090/public-dashboards/ef18a1c1b4e74dd8ae09387b86fe16b6?orgId=1&amp;amp;refresh=5s&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1735796745046&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export default function Grafana() {
  return (
    &amp;lt;div className=&quot;container&quot;&amp;gt;
      &amp;lt;div&amp;gt;
        &amp;lt;iframe
          src=&quot;http://localhost:20090/public-dashboards/abcdefgakjdhfkajh?orgId=1&amp;amp;refresh=5s&quot;
          width=&quot;100%&quot;
          height=&quot;1024&quot;
          frameborder=&quot;0&quot;
          title=&quot;grafana&quot;
        &amp;gt;&amp;lt;/iframe&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;App.js&lt;/p&gt;
&lt;pre id=&quot;code_1735796764993&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import Grafana from &quot;./Grafana&quot;;

function App() {
  return (
    &amp;lt;div className=&quot;App&quot;&amp;gt;
      &amp;lt;Grafana /&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

export default App;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리액트 실행 결과&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1250&quot; data-origin-height=&quot;639&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/z3fst/btsLDmCvnCp/hLK8ROleUpCshkGhIFhj60/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/z3fst/btsLDmCvnCp/hLK8ROleUpCshkGhIFhj60/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/z3fst/btsLDmCvnCp/hLK8ROleUpCshkGhIFhj60/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fz3fst%2FbtsLDmCvnCp%2FhLK8ROleUpCshkGhIFhj60%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1250&quot; height=&quot;639&quot; data-origin-width=&quot;1250&quot; data-origin-height=&quot;639&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그라파나의 대시보드가 통째로 화면에 잘 표시되었음을 확인할 수 있었다.&lt;/p&gt;</description>
      <category>■ 프론트엔드 ■/React</category>
      <category>grafana dashboard react</category>
      <category>grafana in react</category>
      <category>grafana react</category>
      <category>그라파나 대시보드</category>
      <category>그라파나 대시보드 react</category>
      <category>그라파나 대시보드 리액트</category>
      <category>그라파나 대시보드 리액트로 표시하기</category>
      <category>그라파나 리액트 연결</category>
      <category>그라파나 리액트에 표시</category>
      <author>serpiko</author>
      <guid isPermaLink="true">https://serpiko.tistory.com/907</guid>
      <comments>https://serpiko.tistory.com/907#entry907comment</comments>
      <pubDate>Thu, 2 Jan 2025 14:49:43 +0900</pubDate>
    </item>
    <item>
      <title>zustand 메서드 방식과 리듀서 방식</title>
      <link>https://serpiko.tistory.com/906</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;Zustand&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &lt;a href=&quot;https://redux-toolkit.js.org/tutorials/quick-start&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;reduxjs/toolkit&lt;/a&gt; 이 많이 편해지긴 했지만, 여전히 다루기 거대하고 복잡하다&lt;br /&gt;&amp;nbsp; &amp;nbsp;포스팅 게제 현시점 (2024.12.24) &lt;a href=&quot;https://npm-stat.com/charts.html?package=zustand&amp;amp;package=jotai&amp;amp;package=valtio&amp;amp;package=%40reduxjs%2Ftoolkit&amp;amp;package=recoil&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;zustand의 인기와 사용량이 상당히 증가&lt;/a&gt;하였다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 1위가 reduxjs/toolkit 인 것은 여전하다, 그렇지만 zustand가 거의 동일한 수준으로 인지도가 높아졌다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &lt;a href=&quot;https://jotai.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;jotai&lt;/a&gt; 는 3순위 정도 되며, 4순위 &lt;a style=&quot;background-color: #e6f5ff; color: #0070d1; text-align: start;&quot; href=&quot;https://recoiljs.org/ko/docs/introduction/getting-started&quot;&gt;recoil&lt;/a&gt; 과, 5순위 &lt;a href=&quot;https://valtio.dev/docs/introduction/getting-started&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;valtio(어려워 보인다...)&lt;/a&gt; 는 상대적으로 1, 2 순위와 비교하였을 때&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 그 사용량이 매우 저조하다&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1025&quot; data-origin-height=&quot;1052&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ccXZuX/btsLsNofNIf/I7086JL2ZKjgOPIPczumzk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ccXZuX/btsLsNofNIf/I7086JL2ZKjgOPIPczumzk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ccXZuX/btsLsNofNIf/I7086JL2ZKjgOPIPczumzk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FccXZuX%2FbtsLsNofNIf%2FI7086JL2ZKjgOPIPczumzk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1025&quot; height=&quot;1052&quot; data-origin-width=&quot;1025&quot; data-origin-height=&quot;1052&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1045&quot; data-origin-height=&quot;807&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/caIPQu/btsLvlKptQM/mDvtjx7Ec65AFJMvWiitf1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/caIPQu/btsLvlKptQM/mDvtjx7Ec65AFJMvWiitf1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/caIPQu/btsLvlKptQM/mDvtjx7Ec65AFJMvWiitf1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcaIPQu%2FbtsLvlKptQM%2FmDvtjx7Ec65AFJMvWiitf1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1045&quot; height=&quot;807&quot; data-origin-width=&quot;1045&quot; data-origin-height=&quot;807&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;593&quot; data-origin-height=&quot;233&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bB8RGD/btsLu49WFIj/0XDhCwGGr67ls5pNlK5yEk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bB8RGD/btsLu49WFIj/0XDhCwGGr67ls5pNlK5yEk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bB8RGD/btsLu49WFIj/0XDhCwGGr67ls5pNlK5yEk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbB8RGD%2FbtsLu49WFIj%2F0XDhCwGGr67ls5pNlK5yEk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;593&quot; height=&quot;233&quot; data-origin-width=&quot;593&quot; data-origin-height=&quot;233&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &lt;a href=&quot;https://zustand.docs.pmnd.rs/getting-started/comparison#redux&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;zutand는 Redux와 매우 닮아 있으며&lt;/a&gt;, 간단하게는 메서드 방식과 프로젝트 규모와 소스코드가 길어지는 경우&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; redux처럼 리듀서 방식으로 사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;zustand 의 메서드 방식&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;장점&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;간단함&lt;/b&gt;: 불필요한 액션 타입이나 리듀서를 정의하지 않아도 되므로 코드가 간결하고 직관적임.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;빠른 구현&lt;/b&gt;: 단순한 상태 관리에서는 빠르게 구현 가능.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;가독성&lt;/b&gt;: 함수 이름(increment, decrement)이 명확하여 상태를 변경하는 로직이 직관적임.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;단점&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;확장성 부족&lt;/b&gt;: 상태와 액션이 많아질 경우, 모든 로직을 한 파일에 유지해야 하므로 관리가 어려워질 수 있음.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;테스트 어려움&lt;/b&gt;: 각 함수의 로직을 독립적으로 테스트하기 힘듦(리듀서 방식보다 상대적으로).&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;사용 사례&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;상태가 단순하고 액션이 많지 않은 소규모 프로젝트에서 적합.&lt;/li&gt;
&lt;li&gt;간단한 상태 업데이트가 주된 요구사항일 때 선호.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;src/stores/methodCountStore.ts&lt;/p&gt;
&lt;pre id=&quot;code_1735005574141&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { create } from &quot;zustand&quot;;

type State = {
  count: number;
};

type Actions = {
  increment: (qty: number) =&amp;gt; void;
  decrement: (qty: number) =&amp;gt; void;
};

export const useMethodCountStore = create&amp;lt;State &amp;amp; Actions&amp;gt;((set) =&amp;gt; ({
  count: 0,
  increment: (qty: number) =&amp;gt; set((state) =&amp;gt; ({ count: state.count + qty })),
  decrement: (qty: number) =&amp;gt; set((state) =&amp;gt; ({ count: state.count - qty })),
}));&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;src/components/MethodCounter.tsx&lt;/p&gt;
&lt;pre id=&quot;code_1735005613000&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import React from &quot;react&quot;;
import { useMethodCountStore } from &quot;../stores/methodCountStore&quot;;

const MethodCounter = () =&amp;gt; {
  const { count, increment, decrement } = useMethodCountStore();

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;h1&amp;gt;Method Count: {count}&amp;lt;/h1&amp;gt;
      &amp;lt;button onClick={() =&amp;gt; increment(1)}&amp;gt;+1&amp;lt;/button&amp;gt;
      &amp;lt;button onClick={() =&amp;gt; decrement(1)}&amp;gt;-1&amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
  );
};

export default MethodCounter;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;src/App.tsx&lt;/p&gt;
&lt;pre id=&quot;code_1735005643542&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import &quot;./styles.css&quot;;
import MethodCounter from &quot;./components/MethodCounter&quot;;

export default function App() {
  return (
    &amp;lt;div className=&quot;App&quot;&amp;gt;
      &amp;lt;MethodCounter /&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;zustand 의 리듀서 방식&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;장점&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;유사성&lt;/b&gt;: Redux와 같은 리듀서 기반 상태 관리 방식과 유사하므로 Redux 경험이 있는 개발자들이 쉽게 이해하고 적응할 수 있음.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;확장성&lt;/b&gt;: 액션이 많아질 경우, 리듀서를 별도 파일로 분리하여 상태 관리와 비즈니스 로직을 모듈화할 수 있음.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;테스트 용이성&lt;/b&gt;: 리듀서 로직을 독립적으로 테스트하기 쉬움.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;단점&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;간단한 상태 관리에 불필요한 복잡성&lt;/b&gt;: 리듀서 함수와 액션 타입을 정의해야 하므로 초기 설정이 비교적 번거로움.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;가독성 저하&lt;/b&gt;: 코드의 길이가 길어지고, 디스패치를 사용하는 방식이 직관적이지 않을 수 있음.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;사용 사례&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;상태가 복잡하고 액션이 많은 대규모 프로젝트에서 적합.&lt;/li&gt;
&lt;li&gt;상태 관리 로직이 단순하지 않은 경우(다양한 액션 타입과 비즈니스 로직이 필요한 경우) 선호.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;src/stores/countStore.ts&lt;/p&gt;
&lt;pre id=&quot;code_1735005825768&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { create } from &quot;zustand&quot;;

type State = {
  count: number;
};

type Actions = {
  increment: (qty: number) =&amp;gt; void;
  decrement: (qty: number) =&amp;gt; void;
};

type Action = {
  type: keyof Actions;
  qty: number;
};

type Dispatch = {
  dispatch: (action: Action) =&amp;gt; void;
};

const countReducer = (state: State, action: Action): State =&amp;gt; {
  switch (action.type) {
    case &quot;increment&quot;:
      return { count: state.count + action.qty };
    case &quot;decrement&quot;:
      return { count: state.count - action.qty };
    default:
      throw new Error(`Unhandled action type: ${action.type}`);
  }
};

export const useCountStore = create&amp;lt;State &amp;amp; Dispatch&amp;gt;((set) =&amp;gt; ({
  count: 0,
  dispatch: (action: Action) =&amp;gt; set((state) =&amp;gt; countReducer(state, action)),
}));&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;src/components/Counter.tsx&lt;/p&gt;
&lt;pre id=&quot;code_1735005894141&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import React from &quot;react&quot;;
import { useCountStore } from &quot;../stores/countStore&quot;;

const Counter = () =&amp;gt; {
  const { count, dispatch } = useCountStore();

  const handleIncrement = () =&amp;gt; {
    dispatch({ type: &quot;increment&quot;, qty: 1 });
  };

  const handleDecrement = () =&amp;gt; {
    dispatch({ type: &quot;decrement&quot;, qty: 1 });
  };

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;h1&amp;gt;Count: {count}&amp;lt;/h1&amp;gt;
      &amp;lt;button onClick={handleIncrement}&amp;gt;+1&amp;lt;/button&amp;gt;
      &amp;lt;button onClick={handleDecrement}&amp;gt;-1&amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
  );
};

export default Counter;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;src/App.tsx&lt;/p&gt;
&lt;pre id=&quot;code_1735005909168&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import &quot;./styles.css&quot;;
import Counter from &quot;./components/Counter&quot;;

export default function App() {
  return (
    &amp;lt;div className=&quot;App&quot;&amp;gt;
      &amp;lt;Counter /&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;결론&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;초기 상태가 단순&lt;/b&gt;하고 액션이 몇 개 없다면, &lt;b&gt;메서드 방식&lt;/b&gt;을 사용&lt;/li&gt;
&lt;li&gt;&lt;b&gt;복잡한 상태 관리&lt;/b&gt;나 상태 변경 로직이 많아질 경우, &lt;b&gt;리듀서 방식&lt;/b&gt;으로 전환하는 것이 좋을듯&lt;/li&gt;
&lt;li&gt;프로젝트 초기에는 간단한 방식으로 시작하고, 복잡성이 증가하면 리듀서 방식으로 리팩터링하는 것도 좋은 접근일 듯 하다&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;위의 예제 실제 코드 보기&lt;/h3&gt;
&lt;p&gt;&lt;iframe src=&quot;https://codesandbox.io/embed/jyfdzf?view=Editor+%2B+Preview&amp;amp;module=%2Fsrc%2FApp.js&amp;amp;hidenavigation=1&quot; width=&quot;100%&quot; height=&quot;800px&quot;&gt;&lt;/iframe&gt;&lt;/p&gt;</description>
      <category>■ 프론트엔드 ■/React</category>
      <category>react zustand</category>
      <category>zustand</category>
      <category>zustand redux</category>
      <category>zustand 상태관리</category>
      <category>리액트 zustand</category>
      <category>리액트 상태관리 순위</category>
      <category>리액트 전역 상태관리</category>
      <category>리액트 전역 상태관리 순위</category>
      <category>저스탄드 사용법</category>
      <category>주스탄드 상태관리</category>
      <author>serpiko</author>
      <guid isPermaLink="true">https://serpiko.tistory.com/906</guid>
      <comments>https://serpiko.tistory.com/906#entry906comment</comments>
      <pubDate>Tue, 24 Dec 2024 11:07:58 +0900</pubDate>
    </item>
    <item>
      <title>react using state when you don't need it</title>
      <link>https://serpiko.tistory.com/905</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리액트의 useState가 필요없을 때, 혹은 form 에서 useState를 언제쓰는가에 대한 설명&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;input 값을 입력받고 보여줄 때, useState를 사용하지 않아도 된다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;useState를 배제하므로써, 리렌더링 없앨 수 있다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;iframe src=&quot;https://codesandbox.io/embed/c2px9k?view=Editor+%2B+Preview&amp;amp;module=%2Fsrc%2FApp.js&quot; width=&quot;100%&quot; height=&quot;800px&quot;&gt;&lt;/iframe&gt;&lt;/p&gt;</description>
      <category>■ 프론트엔드 ■/React</category>
      <category>form usestate</category>
      <category>reacr form</category>
      <category>react input ref</category>
      <category>react input state</category>
      <category>react input useref</category>
      <category>react input usestate</category>
      <category>react usestate 대신 useref</category>
      <author>serpiko</author>
      <guid isPermaLink="true">https://serpiko.tistory.com/905</guid>
      <comments>https://serpiko.tistory.com/905#entry905comment</comments>
      <pubDate>Fri, 29 Mar 2024 10:05:49 +0900</pubDate>
    </item>
    <item>
      <title>React Hook Form: FormProvider-useFormContext</title>
      <link>https://serpiko.tistory.com/904</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #0e101c; color: #ffffff; text-align: start;&quot;&gt;- ContextAPI를 이용하여 Sub.js에서 사용한 값을 App.js 에서도 감지가 가능하다&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;iframe src=&quot;https://codesandbox.io/embed/94w87h?view=Editor+%2B+Preview&amp;amp;module=%2Fsrc%2FApp.js&quot; width=&quot;100%&quot; height=&quot;800px&quot;&gt;&lt;/iframe&gt;&lt;/p&gt;</description>
      <category>■ 프론트엔드 ■/React</category>
      <category>react-hook-form contextAPI</category>
      <category>react-hook-form FormProvider</category>
      <category>react-hook-form useFormContext</category>
      <category>react-hook-form 부모자식 통신하기</category>
      <category>react-hook-form 여러 컴포넌트 값 가져오기</category>
      <author>serpiko</author>
      <guid isPermaLink="true">https://serpiko.tistory.com/904</guid>
      <comments>https://serpiko.tistory.com/904#entry904comment</comments>
      <pubDate>Fri, 29 Mar 2024 09:59:48 +0900</pubDate>
    </item>
    <item>
      <title>React Hook Form (useState-less 패턴)</title>
      <link>https://serpiko.tistory.com/903</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #0e101c; color: #ffffff; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;- RHF에 내장된 FormProvider, useOrderFormContext를 이용하여 ContextAPI구현&lt;/p&gt;
&lt;p style=&quot;background-color: #0e101c; color: #ffffff; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;- Control을 주입받은 컴포넌트로 모든 컴포넌트는 같은 useForm 생성 시점과 일치 시킨다&lt;/p&gt;
&lt;p style=&quot;background-color: #0e101c; color: #ffffff; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;- setValue, resetField, useWatch 이용하여 useState와 리렌더링 없이 양방향 값 핸들링하고 연산&lt;/p&gt;
&lt;p style=&quot;background-color: #0e101c; color: #ffffff; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;- 제출(Submit)시, 컴포넌트에 정의된 name 기준으로 값들을 반환한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;iframe src=&quot;https://codesandbox.io/embed/yk5k23?view=Editor+%2B+Preview&amp;amp;module=%2Fsrc%2FApp.tsx&quot; width=&quot;100%&quot; height=&quot;800px&quot;&gt;&lt;/iframe&gt;&lt;/p&gt;</description>
      <category>■ 프론트엔드 ■/React</category>
      <category>react-hook-form</category>
      <category>react-hook-form control</category>
      <category>react-hook-form getValues</category>
      <category>react-hook-form resetField</category>
      <category>react-hook-form setValue</category>
      <category>react-hook-form submit</category>
      <category>react-hook-form useState</category>
      <category>react-hook-form useState less</category>
      <category>react-hook-form useState 없이 사용하기</category>
      <category>react-hook-form useWatch</category>
      <author>serpiko</author>
      <guid isPermaLink="true">https://serpiko.tistory.com/903</guid>
      <comments>https://serpiko.tistory.com/903#entry903comment</comments>
      <pubDate>Fri, 29 Mar 2024 09:50:03 +0900</pubDate>
    </item>
    <item>
      <title>re-resizeable 을 이용한 오더북 개수조정 컴포넌트</title>
      <link>https://serpiko.tistory.com/902</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;- 박스 우측 하단을 드래그하여 리사이즈가 가능한데, 리사이즈가 될 때 박스 안의 내용은 계속 중앙정렬 되도록 한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 박스 우측 하단 드래그는 최소, 최대로 높이가 제한되어있다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 기본 포지션별로 15개씩&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 리사이즈 할 때 최소 수량은 포지션별 10개씩&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 리사이즈 할 때 최대 수량은 포지션별 20개씩&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리액트 코드로 구현해보면 다음과 같다&lt;/p&gt;
&lt;p&gt;&lt;iframe src=&quot;https://codesandbox.io/embed/ydmg48?view=Editor+%2B+Preview&amp;amp;module=%2Fsrc%2Findex.js&quot; width=&quot;100%&quot; height=&quot;800px&quot;&gt;&lt;/iframe&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원본코드&lt;/p&gt;
&lt;pre id=&quot;code_1707405592343&quot; class=&quot;javascript&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;import React, { useState } from &quot;react&quot;;
import { render } from &quot;react-dom&quot;;
import { Resizable } from &quot;re-resizable&quot;;

const style = {
  display: &quot;flex&quot;,
  // flexDirection: &quot;column&quot;, // 내부 요소들을 세로로 배치하기 위해 추가
  alignItems: &quot;center&quot;,
  justifyContent: &quot;center&quot;,
  border: &quot;solid 1px #ddd&quot;,
  background: &quot;#f0f0f0&quot;,
  overflow: &quot;hidden&quot;,
};

const tickSize = {
  height: &quot;22px&quot;,
  //border: &quot;solid 1px #FF0000&quot;,
};

const buttonStyle = {
  padding: &quot;10px 20px&quot;,
  fontSize: &quot;16px&quot;,
};

const orderStateStyle = {
  fontSize: &quot;22px&quot;,
  width: &quot;100%&quot;,
  height: &quot;70px&quot;,
  marginTop: &quot;10px&quot;,
  backgroundColor: &quot;skyblue&quot;,
};
const resizeHandleStyle = {
  position: &quot;absolute&quot;,
  bottom: -2,
  right: -5,
  width: &quot;20px&quot;,
  height: &quot;20px&quot;,
  background:
    &quot;url('https://upload.wikimedia.org/wikipedia/commons/1/16/MRO_LETTER_NGI.svg')&quot;, // 아이콘 이미지 경로로 대체
  backgroundSize: &quot;contain&quot;,
  backgroundRepeat: &quot;no-repeat&quot;,
};

const App = () =&amp;gt; {
  const [size, setSize] = useState({ width: 300, height: 682 });
  const handleSize = (w, h) =&amp;gt; {
    setSize({ width: w, height: h });
  };
  let buyOrders = Array.from({ length: 20 }, (_, i) =&amp;gt; ({
    price: i + 1,
  })).reverse();
  let sellOrders = Array.from({ length: 20 }, (_, i) =&amp;gt; ({
    price: i + 11,
  })).reverse();

  const incrementSequence = (start, end, increment) =&amp;gt; {
    return Array.from(
      { length: Math.floor((end - start) / increment) + 1 },
      (_, index) =&amp;gt; start + index * increment
    );
  };
  return (
    &amp;lt;div&amp;gt;
      &amp;lt;div style={{ display: &quot;flex&quot; }}&amp;gt;
        &amp;lt;Resizable
          as=&quot;div&quot;
          style={style}
          defaultSize={size}
          enable={{
            right: true,
            bottom: true,
            bottomRight: true,
          }}
          minWidth={100}
          maxWidth={300}
          minHeight={462}
          maxHeight={902}
          grid={[1, 1]}
          snap={{
            x: incrementSequence(100, 300, 20),
            y: incrementSequence(462, 902, 44),
          }}
          snapGap={0}
          size={size}
          onResizeStop={(e, direction, ref, d) =&amp;gt; {
            setSize({
              width: size.width + d.width,
              height: size.height + d.height,
            });
          }}
        &amp;gt;
          &amp;lt;div
            style={{ overflow: &quot;hidden&quot;, width: &quot;100%&quot;, textAlign: &quot;center&quot; }}
          &amp;gt;
            {sellOrders.map((order, i) =&amp;gt; (
              &amp;lt;div style={{ ...tickSize }}&amp;gt;매도 {order.price}&amp;lt;/div&amp;gt;
            ))}
            &amp;lt;div style={{ ...tickSize, border: &quot;1px solid red&quot; }}&amp;gt;
              현재값 표시
            &amp;lt;/div&amp;gt;
            {buyOrders.map((order) =&amp;gt; (
              &amp;lt;div style={{ ...tickSize }}&amp;gt;매수 {order.price}&amp;lt;/div&amp;gt;
            ))}
          &amp;lt;/div&amp;gt;
          &amp;lt;div className=&quot;resize-handle&quot; style={resizeHandleStyle}&amp;gt;&amp;lt;/div&amp;gt;
        &amp;lt;/Resizable&amp;gt;
        &amp;lt;div style={{ width: &quot;100%&quot;, paddingLeft: &quot;20px&quot; }}&amp;gt;
          &amp;lt;button style={buttonStyle} onClick={() =&amp;gt; handleSize(300, 462)}&amp;gt;
            최소 (10개씩 x 2)
          &amp;lt;/button&amp;gt;
          &amp;lt;button style={buttonStyle} onClick={() =&amp;gt; handleSize(300, 682)}&amp;gt;
            기본값 (15개씩 x 2)
          &amp;lt;/button&amp;gt;
          &amp;lt;button style={buttonStyle} onClick={() =&amp;gt; handleSize(300, 902)}&amp;gt;
            최대 (20개씩 x 2)
          &amp;lt;/button&amp;gt;
        &amp;lt;/div&amp;gt;
      &amp;lt;/div&amp;gt;
      &amp;lt;div style={orderStateStyle}&amp;gt;주문현황...&amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
  );
};

render(&amp;lt;App /&amp;gt;, document.getElementById(&quot;root&quot;));&lt;/code&gt;&lt;/pre&gt;</description>
      <category>■ 프론트엔드 ■/React</category>
      <category>react re-size</category>
      <category>react resize</category>
      <category>react 리사이즈</category>
      <category>react 사이즈</category>
      <category>react 사이즈 조절 드래그</category>
      <category>react 사이즈조절</category>
      <category>리액트 드래그 사이즈조절</category>
      <category>리액트 사이즈</category>
      <category>리액트 사이즈 조절</category>
      <author>serpiko</author>
      <guid isPermaLink="true">https://serpiko.tistory.com/902</guid>
      <comments>https://serpiko.tistory.com/902#entry902comment</comments>
      <pubDate>Fri, 9 Feb 2024 00:50:01 +0900</pubDate>
    </item>
    <item>
      <title>FLfile.remove로 파일 혹은 폴더 삭제하기</title>
      <link>https://serpiko.tistory.com/901</link>
      <description>&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;a href=&quot;https://serpiko.tistory.com/guestbook#comment8893801&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://serpiko.tistory.com/guestbook#comment8893801&lt;/a&gt; 질문에 대한 답글&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;FLfile 객체&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;목적&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- FLfile API를 사용하여 파일 시스템에 접근하는 Flash 확장 기능 작성&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;설명&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- FLfile 객체는 Flash MX 2004 7.2(..무려 20년;;) 에서부터 사용할 수 있으며&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 로컬 파일 시스템의 파일과 폴더에 접근, 수정, 삭제할 수 있는 Flash 확장 기능을 작성할 수 있게한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- FLfile 객체는 JavaScript API를 확장한 형태로 제공된다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 이 확장은 공유 라이브러리이며 다음 폴더에 위치한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Windows 7, 8&lt;/p&gt;
&lt;pre id=&quot;code_1705934806739&quot; class=&quot;bash&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;boot drive\Users\username\AppData\Local\Adobe\Flash CC\language\Configuration\External Libraries\FLfile.dll&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Max OS X&lt;/p&gt;
&lt;pre id=&quot;code_1705934834467&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Macintosh HD/Users/username/Library/Application Support/Adobe/Flash CC/language/Configuration/External Libraries/FLfile.dll&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- FLfile 메서드는 파일 또는 폴더(디렉토리)를 다루며, 파일이나 폴더의 위치를 지정하는 하나 이사으이 매개변수를 취한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 위치는 웹 사이트 URL과 매우 유사한 형식의 문자열로 표현되며, 파일 URL(Uniform Resource Identifier)이라 한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 다음과 같은 형식으로 지정된다 (따옴표 포함)&lt;/p&gt;
&lt;pre id=&quot;code_1705935023141&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&quot;file:///drive|/folder 1/folder 2/.../filename&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;예시&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- C드라이브에 &quot;config&quot; 라는 폴더를 만들고 &quot;Program Files/MyApp&quot; 폴더에 저장하려면 다음 명령을 사용한다.&lt;/p&gt;
&lt;pre id=&quot;code_1705935085790&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;FLfile.createFolder(&quot;file:///C|/Program Files/MyApp/config&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 그 폴더에 &quot;config.ini&quot; 파일을 만드려면 아래와 같이&lt;/p&gt;
&lt;pre id=&quot;code_1705935112441&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;FLfile.write(&quot;file:///C|/Program Files/MyApp/config/config.ini&quot;, &quot;&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Mac에서 폴더를 만드려면 다음 명령어를 사용할 수 있다&lt;/p&gt;
&lt;pre id=&quot;code_1705935142708&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;FLfile.createFolder(&quot;file:///Macintosh/MyApp/config&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;FLfile.remove()&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;사용&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;FLfile.remove(fileOrFolderURI)&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;매개변수&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;fileOrFolderURI: 삭제하려는 파일 또는 폴더를 지정하는 문자열(`file:///URI`로 표시해야 함)&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;반환값&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Boolean: 성공시 true, 실패하면 false&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;설명&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지정된&amp;nbsp;파일이나&amp;nbsp;폴더를&amp;nbsp;삭제합니다.&amp;nbsp;폴더에&amp;nbsp;파일이&amp;nbsp;포함된&amp;nbsp;경우&amp;nbsp;해당&amp;nbsp;파일도&amp;nbsp;삭제됩니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;R(읽기 전용) 권한이 부여된 경우, 제거할 수 없습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;예시&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음의 예는 `file:///c|/temp/mydata.txt` 파일을 삭제하기위한 예제이다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 삭제할 프롬프트를 입력받고 해당 파일이 존재하면 사용자에게 경고한뒤 `y 혹은 Y'를 선택하면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 파일을 삭제하고 그 결과를 사용자에게 알럿창으로 알린다&lt;/p&gt;
&lt;pre id=&quot;code_1705935653607&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var fileURI = prompt (&quot;삭제할 파일 혹은 폴더를 입력하세요: &quot;, &quot;file:///c|/temp/delete.txt&quot;);
if (FLfile.exists(fileURI)) {
	var confirm = prompt(&quot;파일이 존재합니다 삭제할까요?? (y/n)&quot;, &quot;y&quot;);
	if (confirm == &quot;y&quot; || confirm == &quot;Y&quot;) {
		if(FLfile.remove(fileURI)) {
			alert(fileURI + &quot; 파일이 삭제되었습니다.&quot;);
		} else {
			alert(&quot;다음 경로의 파일을 삭제에 실패하였습니다 &quot; + fileURI);
		}
	}
} else {
  alert(fileURI + &quot; 해당 경로는 파일이 존재하지 않습니다.&quot;);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음의 예는 `file:///c|/Users/myname/Downloads/test` 폴더를 바로 삭제하는 예이다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 스크립트가 구동되면 해당 경로의 폴더를 바로 삭제하고 그 결과를 output panel에 알린다&lt;/p&gt;
&lt;pre id=&quot;code_1705936120929&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var fileURI = &quot;file:///c|/Users/myname/Downloads/test&quot;;
if(FLfile.exists(fileURI)){
  if(FLfile.remove(fileURI)){
    fl.trace(fileURI + &quot; 가 삭제되었습니다&quot;);
  } else {
  	fl.trace(&quot;삭제에 실패했습니다 &quot; + fileURI)
  }
} else {
  fl.trace(fileURI + &quot; 해당 경로는 파일이 존재하지 않습니다.&quot;);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;응용의 예) 주의!!. 프로그램을 실행해 볼 수 없어서 가능한지에 대한 여부를 테스트해봐야 함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 특정 폴더의 모든 파일은 =&amp;gt; var fileURI = &quot;file:///c|/Users/myname/Downloads/test/*&quot;;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 특정 폴더의 모든 `.mov` 파일은 =&amp;gt; var fileURI = &quot;file:///c|/Users/myname/Downloads/test/*.mov&quot;;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 특정 폴더 안에 폴더가 여러있어도 그 안의 모든 .mov 파일`은&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp;var fileURI = &quot;file:///c|/Users/myname/Downloads/**/*.mov&quot;;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>■ 플래시 ■/Adobe Flash CS6</category>
      <author>serpiko</author>
      <guid isPermaLink="true">https://serpiko.tistory.com/901</guid>
      <comments>https://serpiko.tistory.com/901#entry901comment</comments>
      <pubDate>Tue, 23 Jan 2024 00:30:47 +0900</pubDate>
    </item>
  </channel>
</rss>