[Enact] Enact 프레임워크 기본 개념 및 예시

새 프로젝트 진행에 앞서 내가 보려고 만드는 Enact 프레임워크 정리

Frontend
2024년 1월 2일

저희 팀은 현재 2024년 신규 프로젝트로 enact framework를 채택했습니다.
생소하기도 했지만, React.js 의 framework 이고,
현재 저희 팀이 가장 잘 익숙하게 잘 다룰 수 있는 React 기반의 framework라고 하니 거부감보다는 신선함과, 흥미로움이 더욱 생기게 되었습니다.

현재 스터디 중이므로 정확하지 않을 수 있습니다.

Enact 란?

Enact란, 웹 어플리케이션을 구축하기 위한 Javascript의 프레임워크입니다.
React.js 기반으로 구축되었기에 편의 상 React.js의 프레임워크라고도 할 수 있습니다.

Enact는 주로 TV와 같은 대형화면을 가진 디바이스에서의 사용을 염두에 두고 설계되었고,
굉장히 유연한 설계 방식을 제공하면서도, 요즘 front-end 에서는 기본 소양이라고도 할 수 있는 React를 기반으로 하여 구축되었기에
개발자들이 쉽게 접근이 가능하다는 장점이 있습니다.

내가 느낀 Enact의 장점

우선 Enact는 앞서 말한 것과 같이 TV와 같은 대형 화면의 디바이스에서의 사용을 위해 설계되었기에,
4방향 포커싱에 대해 기능을 쉽게 구현할 수 있도록 지원이 되어있습니다.

단순 React 환경이라면, 키보드의 4방향과 관련된 로직을 따로 작성해주어야 하는데,
Enact에서는 그럴 필요가 없으니, 코드가 굉장히 간결해지고 깔끔해지는 이점이 있는 것 같습니다.

이 부분에서 Enact를 채택하게 되었습니다.

뿐만 아니라, Enact는 접근성을 굉장히 중요하게 생각하기에, 웹 콘텐츠의 접근성 지침을 준수하는 어플리케이션을 구축할 수 있도록 다양한 도구와 컴포넌트를 지원하고있습니다.

실제 예시를 통해 Enact가 얼마나 편리한지 설명이 가능합니다.

  • React 에서의 4방향 포커싱 처리

React 에서는 따로 4방향 포커싱 처리에 관한 기능이 제공되어있지 않으므로, 개발자가 직접 키보드 이벤트에 관한 처리를 직접 해주어야합니다.

쉬운 예로 다음 인덱스번호의 컴포넌트로 포커싱을 이동하는 효과를 구현해보겠습니다.

interface FocusableButtonProps {
  children: React.ReactNode;
  onFocused: () => void;
}
 
const FocusableButton = ({children, onFocused}: FocusableButtonProps) => {
  <button tabIndex={-1} onFocus={onFocused}>{children}</button>
}
 
export default function Component() {
  const [focusedIndex, setFocusedIndex] = useState(0)
 
  const handleKeyDown = useCallback((event: KeyboardEvent) => {
    const {keyCode} = event;
    const focusableElements = Array.from(document.querySelectorAll('button'));
    const currentIndex = focusableElements.indexOf(document.activeElement as HTMLButtonElement);
    let nextIndex = currentIndex;
 
    switch (keyCode) {
      case 37:
      case 38:
      nextIndex = Math.max(0, currentIndex - 1);
      break;
 
      case 39:
      case 40:
      nextIndex = Math.min(focusableElements.length - 1, currentIndex + 1)
      break;
 
      default:
        return;
      }
 
      setFocusedIndex(nextIndex)
      focusableElements[nextIndex].focus();
      event.preventDefault();
      }, [])
 
    useEffect(() => {
      window.addEventListener('keydown', handleKeyDown)
 
      return () => {
        window.removeEventListener('keydown', handleKeyDown)
      }
    }, [handleKeyDown])
 
    useEffect(() => {
      const focusableElements = Array.from(document.querySelectorAll('button'))
 
      if (focusableElements.length > 0) {
        focusableElements[focusedIndex].focus();
      }
    }, [focusedIndex])
 
    return (
      <>
        <FocusableButton onFocused={() => setFocusedIndex(0)}>Button 1</FocusableButton>
        <FocusableButton onFocused={() => setFocusedIndex(1)}>Button 2</FocusableButton>
        <FocusableButton onFocused={() => setFocusedIndex(2)}>Button 3</FocusableButton>
      <>
    )
  }
 

위 코드는 3개의 버튼 내에서 키보드 방향키를 이용한 포커싱 이동을 구현한 것입니다.
사실 크게 복잡하지는 않은 로직이지만, 단순 포커싱만을 처리하기에는 너무 많은 내용을 담고 있습니다.
물론 이러한 것들은 따로 util 폴더를 통해 포커싱에 관련된 함수를 만들어 재사용성을 높여 사용할 수는 있지만,
Enact를 사용하게 되면 이러한 작업마저도 불필요해집니다.

  • Enact 에서의 4방향 포커싱 처리
import { SpotlightContainerDecorator } from "@enact/spotlight/SpotlightContainerDecorator";
import { Spottable } from "@enact/spotlight/Spottable";
 
const Container = SpotlightContainerDecorator("div");
 
const SpottableButton = Spottable("button");
 
export default function Component() {
  return (
    <Container>
      <SpottableButton>Button 1</SpottableButton>
      <SpottableButton>Button 2</SpottableButton>
      <SpottableButton>Button 3</SpottableButton>
    </Container>
  );
}

딱 봐도 어마어마한 양의 코드가 줄었고, 훨씬 보기 편하게 깔끔해졌습니다.
React 내에서는 따로 구현을 해야만 했던 4방향 포커싱 기능을 Enact 에서는 Enact에서 제공해주는 Spotlight 기능만 사용하면 편리하게 구현이 가능합니다.

물론 현재 이 코드만 봐서는 SpotlightContainerDecorator가 무엇인지, Spottable이 무엇인지 알 수 없지만,
해당 내용은 다음 포스팅에서 설명하기로 하고, 우선 코드의 간결함에 대해서 집중해보도록 하겠습니다.

이처럼 Enact 에는 자체적으로 포커싱에 대한 처리가 지원이 되어, 코드를 좀 더 편하게 작성할 수 있어
기능적인 로직 구현에만 온전히 집중할 수 있도록 도움을 주고있습니다.

그럼 Enact의 단점은 ?

Enact의 편의성이 실로 대단하지만, Enact는 사실 TV 같은 키보드 포커싱 처리가 굳이 필요없다면 사용하지 않아도 될 framework 입니다.
또한, 이건 실제로 개발 초기 셋팅을 진행하면서 느꼈던 부분인데

공식문서가 굉장히 부족합니다.

공식문서를 보면 알겠지만, 각각의 기능에 대해서 설명이 굉장히 부족합니다.
때문에 개발 초기셋팅을 진행하면서 라이브러리와 버전 호환 등의 이슈로 라이브러리 교체를 몇 번이나 진행한 이력이 있습니다.

근데 이는 사실 내가 진행할 프로젝트가 webOS 지원 버전이 Chrome 38 부터 지원해야하므로, webOS 버전 자체의 이슈도 있습니다.

실제로 webOS 3.0 버전부터 지원을 하려면 Chrome 38 버전에서 작동이 가능해야하는데,
너무 옛날 버전이다보니 enact/cli의 버전이 최신 버전이라면 현재 사용이 불가능합니다.

또한, ES6 문법을 지원하지 않아서, babel로 하나하나 설정을 해줘야하는 번거로움이 있었으며,
그 마저도 *"원인을 파악하지 못한 이슈"*가 여러 부분 발생했었습니다.

프로젝트를 진행하며 상태 관리를 위해 Redux-toolkit을 채택했는데
무슨 이유에선지 build 를 하고 실제 webOS 3.0 TV에 앱을 실행시켜보니 흰 화면만 노출되었습니다.

찾아보니, redux-toolkit 라이브러리 내의 optional-chaining이 문제였는데,
바벨 설정을 통해 이를 수정해보아도 전혀 해결되지 않았습니다.

그래서 전통적인 방식의 redux를 사용하니 잘 되었습니다.
오랜만에 전통적인 방식의 redux를 사용하니 뭔가 감회가 색다르긴 했습니다.

같은 이유로 webOS 3.0과 같은 낮은 버전에서는 typescript 사용이
불가능합니다.

나에게 있어 이 부분이 가장 큰 문제라고 생각합니다.
규모가 꽤 있는 프로젝트를 진행하고 있는데, typescript 사용이 불가능하니 유지보수 측면에서도 난관에 봉착할 미래가 훤히 보였습니다.
그래서 저희 팀은 Reactprop-types를 사용해서 어느 정도 문제를 해결하려고 하고 있는데
사실 컴파일 단계에서 오류를 잡아주는 부분이 아니라 근본적인 문제 해결을 할 수는 없을 것 같습니다.

구글링을 해도 정보가 거의 없습니다.

현재까지는 공식문서를 열심히 참고하며, 개발 가이드를 익히고 있지만, 설명이 조금 부족한 내용에 대해 참고할 만한 reference가 별로 없는 것이 문제입니다.

마치며..

다행히 아직까지는 개발을 진행함에 있어 큰 이슈가 나지 않았고, 해결 방법이 있어 초기 셋팅에 있어서는 아직까지는 문제가 없습니다.

아쉬운 부분도 다소 있지만, 4방향 포커싱에 관해서 아주 대단한 기능을 제공해주다보니, 위의 단점들은 어느정도 상쇄가 되는 것 같습니다.
처음에 "이게 돼?" 하며 걱정도 했지만, 새로운 기술을 접하다보니 나름 재미도 있고 생각보다 어렵지 않았습니다.

focusing에 관련해서 다양한 가이드를 제공하고 있는데, 이 부분에 관해서도 스터디를 진행하며 포스팅할 예정입니다.

Tags:
Enact