피그마 플러그인 동작 로직

Hee·2023년 6월 22일
0

급하게 피그마 플러그인을 개발하기로 하면서 웹 서비스의 기존 기능 중 어떤 것을 넣고 빼야할 지를 기획했다.
사용자를 특정하는 부분이나 페이지 전환에 있어 새로운 방식을 적용하고 플러그인 코드와 UI 사이에서 주고받는 로직을 처음 접하다 보니 초반에 고민을 꽤 했다.

로직을 담당하는 부분과 UI를 담당하는 부분이 컴파일되어 Figma 내에서 실행되는 방식이다.
UI와 로직은 figma.ui.postMessage와 figma.ui.onmessage를 통해 메시지를 주고받는다. 이부분에 대해서 간단하게 알아볼 예정이다.

초기 세팅

피그마 플러그인 개발은 HTML, CSS, JS으로 개발가능하다.
여기에 webpack 등의 번들러 설정을 추가하게 되면 웹서비스 개발과 마찬가지로 React +
TypeScript 사용이 가능하다.

피그마 플러그인을 위한 보일러 플레이트가 다양한데
React + TypeScript와 StyledComponents을 사용하여 개발하고자 하여 아래 친절하게 만들어주신 보일러플레이트를 이용해보겠다.

보일러 플레이트: https://github.com/hseoy/figma-plugin-react-boilerplate

$ npx degit https://github.com/hseoy/figma-plugin-react-boilerplate <project name>
$ cd <project name>
$ npm install
$ npm run build

내 파일구성

UI와 플러그인 로직 코드 사이 메시지 주고받기

UI를 제공하는 피그마 플러그인을 구현할 때는 샌드박스와 UI 상의 통신을 하게 되는 데 Window 객체 사이에서 메시지를 전달할 때 사용하는 postMessage를 이용합니다

미묘하게 다른점

  • UI 내부에서는 pluginMessage 속성에 대한 값을 보냅니다
  • 플러그인 코드에서는 보내려는 값을 직접 보내고 받습니다.
ui에서 플러그인 코드로 메시지 보내기
parent.postMessage({pluginMessage: 'anything here'},'*')

플러크인 코드에서 메시지 수신
figma.ui.onmessage=(message) => {
console.log('got this from the UI', message)
}
플러그인 코드에서 UI로 메시지 보내기
figma.ui.postMessage(42)

UI에서 해당 메시지 수신
onmessage = (event) => {
console.log('got this from the plugin code', event.data.pluginMessage)
}

로그인

간단한 로그인 로직으로 피그마 플러그인 동작 방식을 알아보자

UI

로그인 화면을 구성하고 로그인 버튼 선택 시 UI에서 플러그인 코드로 메시지를 보낸다.

//src/ui/login.tsx
function Login({ setIsLogin, setIsUser, isUser }) {
  const [errorText, setErrorText] = useState('');
  const [isError, setIsError] = useState(false);
  const [emailValue, setEmailValue] = useState('');
  const apiURL = `${BASE_URL}/auth/user/figma/get/email?email=${emailValue}`;


  const onSendEmail = async (event) => {
    event.preventDefault();
    setErrorText('');
    setIsError(false);
    //ui에서 플러그인 코드로 메시지 보내기 : type과 fetch에 사용할 주소 전송
    window.parent.postMessage(
      { pluginMessage: { type: 'login', apiURL } },
      '*',
    );
  };

  const handleEmail = (e) => {
    setEmailValue(e.target.value);
  };

  const onCheckUser = () => {
     //ui에서 플러그인 코드로 메시지 보내기
    window.parent.postMessage({ pluginMessage: { type: 'check-user' } }, '*');
  };

  return (
    <Container>
      {isUser ? (
        <StartButton type="button" onClick={onCheckUser}>
          시작하기
        </StartButton>
      ) : (
        <>
          <LogoBox>
            <img
              alt="로고"
              style={{ width: '50px', height: '40px', padding: '50px 10px' }}
              src="****"
            />
          </LogoBox>
          <form onSubmit={onSendEmail} className="loginFormBox">
            <LoginBox>
              <EmailInput
                type="text"
                placeholder="이메일을 입력해주세요"
                value={emailValue}
                onChange={handleEmail}
              />
              <LoginButton onClick={onSendEmail}>확인</LoginButton>
              <a
                style={{
                  textDecoration: 'none',
                  color: '#999',
                  fontSize: '12px',
                  padding: '10px',
                }}
                href="https://www.*****/signup"
                target="blank"
              >
                처음 오셨나요?
              </a>
            </LoginBox>
          </form>
          {isError ? <ErrorTextBox>{errorText}</ErrorTextBox> : null}
        </>
      )}

    </Container>
  );
}

export default Login;

플러그인 로직 코드

받은 메시지에 맞는 로직을 실행하고 결과를 다시 UI로 보냄

//src/plugin/index.ts

//보내진 type을 통해 어떤 로직을 실행시켜야 하는지 구분하고 같이 전달받은 정보를 이용(여기서는 apiURL)
figma.ui.onmessage = async (msg) => {
  if (msg.type === 'login') {
    try {
      const response = await fetch(msg.apiURL);
      if (response.status === 200) {
        const result = await response.json();
//로그인 성공 시 피그마 clientStorage에 저장
        await figma.clientStorage.setAsync('email', result.userEmail);
        await figma.clientStorage.setAsync(
          'companyCode',
          result.userCompanyCode,
        );
        //결과를 type과 함께 UI로 메시지 보냄
        figma.ui.postMessage({ type: 'loginSuccess', result });
      } else if (response.status === 401) {
        figma.ui.postMessage({
          type: 'loginError',
          message: '사용자 없음',
        });
        figma.notify('등록된 사용자 없음');
      }
    } catch (error) {
      figma.ui.postMessage({ type: 'error', message: 'API 요청 실패' });
    }
  }
};

실행 결과

로그인 성공 시 메시지 수신 후 useState 변경하여 메인 화면으로 진입한다.

//src/ui/login.tsx

  useEffect(() => {
  //UI쪽에서 메시지 수신하여 사용자 화면 구성
    window.onmessage = (event) => {
      const msg = event.data.pluginMessage;
      if (msg.type === 'loginSuccess') {
        setIsUser(false);
        setIsLogin(true);
      } {중간 생략}
    };
  }, []);
profile
*^^*

0개의 댓글