|
| 1 | +--- |
| 2 | +title: 피그마 플러그인을 React로 만들어보기 |
| 3 | +date: 2023-04-14 |
| 4 | +description: React를 사용하여 피그마 플러그인을 개발하는 방법을 설명합니다. |
| 5 | +category: other |
| 6 | +--- |
| 7 | + |
| 8 | +--- |
| 9 | + |
| 10 | +<div className="mokcha"> |
| 11 | + <div className="mokcha-container"> |
| 12 | + <h2>INDEX</h2> |
| 13 | + <a href="#1" className="mokcha-container__list"> |
| 14 | + 1. 피그마 플러그인은 뭘까? |
| 15 | + </a> |
| 16 | + <a href="#2" className="mokcha-container__list"> |
| 17 | + 2. React로 피그마 플러그인 만들어보기 |
| 18 | + <p>2-1. Config</p> |
| 19 | + <p>2-2. UI 로직 작성</p> |
| 20 | + <p>2-3. Sandbox 로직 작성</p> |
| 21 | + </a> |
| 22 | + </div> |
| 23 | +</div> |
| 24 | + |
| 25 | +--- |
| 26 | + |
| 27 | +<h2 id="1"></h2> |
| 28 | + |
| 29 | +<br></br> |
| 30 | + |
| 31 | +<h2 id="1" className={`dark:text-white text-center`}> |
| 32 | + <div>1. 피그마 플러그인은 뭘까?</div> |
| 33 | +</h2> |
| 34 | + |
| 35 | +<br></br> |
| 36 | + |
| 37 | +피그마 플러그인은 디자인 도구인 <b>피그마(Figma)</b>에서 제공하는 확장 기능입니다. |
| 38 | + |
| 39 | +이 확장 기능을 사용하면, 디자인 작업을 보다 효율적으로 수행할 수 있습니다. 예를 들어, 디자인 작업 중 자주 사용하는 기능을 플러그인으로 만들어 두면, 필요할 때마다 불러와 사용할 수 있습니다. 또한, 피그마 API와 연동하여, 피그마 내에서 디자인을 자동화하거나, 외부 서비스와 연동하여 작업을 수행할 수도 있습니다. |
| 40 | + |
| 41 | +피그마 플러그인은 JavaScript를 사용하여 개발할 수 있으며, React, Vue.js, Angular 등 다양한 프레임워크를 사용하여 개발할 수도 있습니다. 피그마 플러그인 개발을 위한 문서와 도구들이 제공되고 있으며, 개발자는 이를 활용하여 효율적으로 개발할 수 있습니다. |
| 42 | + |
| 43 | +<br></br> |
| 44 | +<h3 className={`dark:text-white`}>피그마 플러그인을 위한 프로젝트 요소</h3> |
| 45 | +<br></br> |
| 46 | + |
| 47 | +피그마 플러그인을 사용할려면 우선 피그마 데스크톱 앱이 필요합니다. |
| 48 | + |
| 49 | +<a |
| 50 | + className={`dark:text-white`} |
| 51 | + target="_blank" |
| 52 | + id="link" |
| 53 | + href="https://www.figma.com/downloads/" |
| 54 | +> |
| 55 | + 피그마 데스크톱 앱 |
| 56 | +</a> |
| 57 | +<br></br> |
| 58 | + |
| 59 | +여기서 본인의 운영체제에 해당하는 앱을 설치하시면 됩니다. 그리고 프로젝트에는 `manifest.json` 파일이 필요합니다. 이 파일은 피그마 플러그인에 대한 정보가 존재합니다. |
| 60 | + |
| 61 | +<br></br> |
| 62 | + |
| 63 | +```json:manifest.json |
| 64 | +{ |
| 65 | + "name": "테스트 플러그인", // 플러그인 이름 |
| 66 | + "id": "00000000", |
| 67 | + "api": "1.0.0", |
| 68 | + "main": "dist/plugin.js", // Sandbox에서 실행될 플러그인 코드 |
| 69 | + "editorType": ["figma", "figjam"], |
| 70 | + "ui": "dist/ui.html" // UI 코드 |
| 71 | +} |
| 72 | +``` |
| 73 | + |
| 74 | +<br></br> |
| 75 | + |
| 76 | +보시면 <b>Sandbox</b>, <b>UI</b> 코드가 <b>분리</b>가 되어있습니다. 피그마 플러그인은 UI와 로직을 분리해서 개발할 수 있습니다. UI는 HTML과 CSS로 구성되며, iframe 위에서 실행됩니다. 로직은 JS로 구성되며, 별도의 sandbox 내에서 실행됩니다. UI와 로직은 `figma.ui.postMessage`와 `figma.ui.onmessage`를 통해 메시지를 주고받을 수 있습니다. |
| 77 | + |
| 78 | +피그마 플러그인 코드가 sandbox와 ui코드가 분리되어 있는 이유는 시스템의 <b>안전성과 성능을 보장</b>하기 위해서입니다. sandbox는 피그마의 핵심적인 로직과 격리되어 있어서 악의적인 코드가 피그마에 영향을 주지 않도록 합니다. 또한 sandbox는 한 번에 하나의 플러그인만 실행할 수 있도록 제한하여 다른 플러그인과의 충돌을 방지합니다. ui코드는 iframe 위에서 실행되어 웹으로 구축된 피그마와는 분리되어 있습니다. 이렇게 하면 ui코드가 피그마의 DOM에 접근하거나 수정하는 것을 막을 수 있습니다. |
| 79 | + |
| 80 | +--- |
| 81 | + |
| 82 | +<h2 id="2"></h2> |
| 83 | + |
| 84 | +<br></br> |
| 85 | + |
| 86 | +<h2 id="2" className={`dark:text-white text-center`}> |
| 87 | + <div>2. React로 피그마 플러그인 만들어보기</div> |
| 88 | +</h2> |
| 89 | + |
| 90 | +<br></br> |
| 91 | + |
| 92 | +<h3 className={`dark:text-white`}>2-1. Config</h3> |
| 93 | +<br></br> |
| 94 | + |
| 95 | +피그마 플러그인 프로젝트를 설정하기 위해서는 너무나 많은 <b>보일러 플레이트</b>가 존재하는데요. 저는 우아한형제들 직원분이 만드신 보일러플레이 repo를 사용했습니다. |
| 96 | + |
| 97 | +<br></br> |
| 98 | + |
| 99 | +<a |
| 100 | + className={`dark:text-white`} |
| 101 | + target="_blank" |
| 102 | + id="link" |
| 103 | + href="https://github.com/hseoy/figma-plugin-react-boilerplate" |
| 104 | +> |
| 105 | + https://github.com/hseoy/figma-plugin-react-boilerplate |
| 106 | +</a> |
| 107 | +<br></br> |
| 108 | + |
| 109 | +```bash |
| 110 | +$ npx degit https://github.com/hseoy/figma-plugin-react-boilerplate <project name> |
| 111 | +$ cd <project name> |
| 112 | +$ yarn install |
| 113 | +$ yarn build |
| 114 | +``` |
| 115 | + |
| 116 | +보일러 플레이트를 빌드까지 성공했다면 다음은 피그마 데스크톱 앱에서 해당하는 플러그인을 불러오는 과정입니다. |
| 117 | + |
| 118 | +1. 피그마 데스크톱 버전을 열어 주세요. |
| 119 | + |
| 120 | +2. 오른쪽 위의 프로필 아이콘 드롭 다운을 클릭한 후 Plugins 선택합니다. |
| 121 | + |
| 122 | +3. In development 섹션에서 + 버튼을 클릭합니다. |
| 123 | + |
| 124 | +4. Import plugin from manifest...를 선택하신 후 다운로드한 보일러 플레이트 내 manifest.json을 선택합니다. |
| 125 | + |
| 126 | +5. 본인이 편집 가능한 디자인 파일에 들어갑니다. |
| 127 | + |
| 128 | +6. Plugins에서 Development 선택 후 보일러 플레이트 플러그인인 sample plugin을 클릭합니다. |
| 129 | + |
| 130 | +<br></br> |
| 131 | +<h3 className={`dark:text-white`}> |
| 132 | + <p>최종 예제 실행 영상</p> |
| 133 | +</h3> |
| 134 | + |
| 135 | +<div className={`flex justify-center`}> |
| 136 | + <video |
| 137 | + controls |
| 138 | + width="40%" |
| 139 | + src="https://user-images.githubusercontent.com/75124028/231973926-ec986d50-f8eb-4e53-86cf-e6319efed46d.mov" |
| 140 | + ></video> |
| 141 | +</div> |
| 142 | + |
| 143 | +<br></br> |
| 144 | +<h3 className={`dark:text-white`}> |
| 145 | + <p>2-2. UI 로직 작성</p> |
| 146 | +</h3> |
| 147 | +<br></br> |
| 148 | + |
| 149 | +첫번째로 UI 로직을 작성합니다. |
| 150 | + |
| 151 | +```ts:App.tsx showLineNumbers |
| 152 | +import React from 'react'; |
| 153 | + |
| 154 | +function App() { |
| 155 | + const requestToPlugin = (payload: string) => { |
| 156 | + parent.postMessage({ pluginMessage: payload }, '*'); |
| 157 | + }; |
| 158 | + |
| 159 | + const 바꿔함수 = () => { |
| 160 | + requestToPlugin('바꿔'); |
| 161 | + }; |
| 162 | + |
| 163 | + const 바꾸지마함수 = () => { |
| 164 | + requestToPlugin('바꾸지마'); |
| 165 | + }; |
| 166 | + |
| 167 | + return ( |
| 168 | + <div> |
| 169 | + <h1>간단한 플러그인</h1> |
| 170 | + <button type="button" onClick={바꿔함수}> |
| 171 | + 바꿔 |
| 172 | + </button> |
| 173 | + <button type="button" onClick={바꾸지마함수}> |
| 174 | + 바꾸지마 |
| 175 | + </button> |
| 176 | + </div> |
| 177 | + ); |
| 178 | +} |
| 179 | + |
| 180 | +export default App; |
| 181 | +``` |
| 182 | + |
| 183 | +바꿔함수가 실행될경우 Sandbox에서 실행될 비즈니스 로직인 `figma.ui.onmessage`가 실행되게 됩니다. 즉 `postMessage()`가 실행될경우 src/plugin의 `figma.ui.onmessage` 함수가 실행됩니다. |
| 184 | + |
| 185 | +이렇게 동작을 분리함으로써 비즈니스 로직과 뷰를 분리합니다. |
| 186 | + |
| 187 | +<br></br> |
| 188 | +<h3 className={`dark:text-white`}> |
| 189 | + <p>2-3. Sandbox 로직 작성</p> |
| 190 | +</h3> |
| 191 | +<br></br> |
| 192 | + |
| 193 | +Sandbox로직은 기존의 React코드와는 다르니 하나씩 설명하겠습니다. 피그마 데스크톱앱에서 플러그인을 실행했을때 ifram을 사용해서 창을 띄운다고 했었는데 띄워주기 위해서는 |
| 194 | + |
| 195 | +```ts |
| 196 | +figma.showUI(__html__); |
| 197 | +``` |
| 198 | + |
| 199 | +<br></br> |
| 200 | + |
| 201 | +이 코드가 필요합니다. `__html__`은 manifest.json에서 명시한 UI HTML 파일의 콘텐츠를 담고 있습니다. |
| 202 | + |
| 203 | +<br></br> |
| 204 | + |
| 205 | +```ts:plugin/index.ts showLineNumbers |
| 206 | +const 바꿔로바꿔 = () => { |
| 207 | + return '바꿔'; |
| 208 | +}; |
| 209 | + |
| 210 | +const 바꾸지마로바꿔 = () => { |
| 211 | + return '바꾸지마'; |
| 212 | +}; |
| 213 | + |
| 214 | +figma.ui.onmessage = async (payload: string) => { |
| 215 | + |
| 216 | + if (payload === '바꿔') { |
| 217 | + const { selection } = figma.currentPage; |
| 218 | + |
| 219 | + selection.forEach((node) => { |
| 220 | + if (node.type === 'TEXT') { |
| 221 | + const translateText = 바꿔로바꿔(); |
| 222 | + node.characters = translateText; |
| 223 | + } |
| 224 | + }); |
| 225 | + } |
| 226 | + |
| 227 | + if (payload === '바꾸지마') { |
| 228 | + const { selection } = figma.currentPage; |
| 229 | + |
| 230 | + selection.forEach((node) => { |
| 231 | + if (node.type === 'TEXT') { |
| 232 | + const translateText = 바꾸지마로바꿔(); |
| 233 | + node.characters = translateText; |
| 234 | + } |
| 235 | + }); |
| 236 | + } |
| 237 | +}; |
| 238 | +``` |
| 239 | + |
| 240 | +위 코드는 피그마 캔버스에서 모든 텍스트 노드를 가져와서 해당 노드의 text값을 바꿔 or 바꾸지마로 바꾸는 로직입니다. |
| 241 | + |
| 242 | +하지만 이 코드를 실행할 경우 <b>에러</b>가 발생하는데요. 그 이유는 텍스트를 다룰 때는 사용할 폰트를 미리 불러와야 한다는 점입니다. 폰트를 불러오기 위해서는 `loadFontAsync api`를 사용해서 불러올수 있습니다. |
| 243 | + |
| 244 | +<br></br> |
| 245 | + |
| 246 | +```ts |
| 247 | +const fontName = { family: 'Roboto', style: 'Regular' }; |
| 248 | + |
| 249 | +figma.ui.onmessage = async (payload: string) => { |
| 250 | + await figma.loadFontAsync(fontName); |
| 251 | + .. |
| 252 | + . |
| 253 | +} |
| 254 | +``` |
| 255 | + |
| 256 | +이렇게 코드 작성을 마치게 되면 정말 간단한 플러그인 완성입니다. |
| 257 | + |
| 258 | +아직도 정확히 플러그인의 동작 과정이 이해되지는 않지만 공부해보면서 처음에는 엄두도 나지 않았던 피그마 플러그인도 만들 수 있었습니다. 물론 너무 간단한 기능만을 구현했지만 이렇게 하나씩 구현해보면서 나중에는 정말 좋은 플러그인을 만들 수 있을 것만 같은 기분입니다. |
| 259 | + |
| 260 | +--- |
| 261 | + |
| 262 | +<br></br> |
| 263 | + |
| 264 | +<b>참고 문서</b> |
| 265 | + |
| 266 | +<br></br> |
| 267 | + |
| 268 | +<a |
| 269 | + className={`dark:text-white`} |
| 270 | + target="_blank" |
| 271 | + id="link" |
| 272 | + href="https://techblog.woowahan.com/8339/" |
| 273 | +> |
| 274 | + https://techblog.woowahan.com/8339/ |
| 275 | +</a> |
| 276 | + |
| 277 | +<a |
| 278 | + className={`dark:text-white`} |
| 279 | + target="_blank" |
| 280 | + id="link" |
| 281 | + href="https://engineering.linecorp.com/ko/blog/create-figma-translation-plugin-with-vuejs?ref=codenary" |
| 282 | +> |
| 283 | + https://engineering.linecorp.com/ko/blog/create-figma-translation-plugin-with-vuejs?ref=codenary |
| 284 | +</a> |
0 commit comments