예시 프로젝트에 미니 앱 프로그래밍 원칙 적용

앱 도메인

웹 앱에 적용된 미니 앱의 프로그래밍 방식을 보여주려면 작지만 충분히 완전한 앱 아이디어가 필요했습니다. 고강도 인터벌 트레이닝 (HIIT)은 짧은 회복 기간과 짧은 기간의 고강도 유산소 운동을 번갈아 가면서 하는 심혈관 운동 전략입니다. 많은 HIIT 트레이닝에서 HIIT 타이머를 사용합니다. 예를 들어 The Body Coach TV YouTube 채널의 30분 온라인 세션을 사용합니다.

초록색 고강도 타이머가 포함된 HIIT 트레이닝 온라인 세션입니다.
활성 기간.
빨간색 저강도 타이머와 함께 HIIT 트레이닝 온라인 세션입니다.
휴식 기간입니다.

HIIT 시간 예시 앱

이 장에서는 'HIIT 시간'이라는 적절한 이름의 HIIT 타이머 애플리케이션의 기본 예를 빌드했습니다. 사용자는 이를 통해 항상 높은 강도 및 저강도 간격으로 구성된 다양한 타이머를 정의하고 관리하며 그중 하나를 학습 세션에 선택할 수 있습니다. 탐색 메뉴, 탭바, 세 페이지가 있는 반응형 앱입니다.

  • 운동: 운동 중 활성화된 페이지입니다. 사용자는 타이머 중 하나를 선택할 수 있으며 세 가지 진행 링(세트 수, 활성 기간, 휴식 시간)이 있습니다.
  • 타이머: 기존 타이머를 관리하고 사용자가 새 타이머를 만들 수 있도록 합니다.
  • 환경설정: 음향 효과 및 음성 출력을 전환하고 언어와 테마를 선택하도록 허용합니다.

다음 스크린샷은 애플리케이션에 대한 인상을 줍니다.

세로 모드의 HIIT 시간 예시 앱
세로 모드의 HIIT 시간 '운동' 탭
가로 모드의 HIIT 시간 예시 앱
가로 모드의 HIIT 시간 '운동' 탭.
타이머 관리를 보여주는 HIIT Time 예시 앱
HIIT 시간 타이머 관리

앱 구조

위에서 설명한 것처럼 앱은 그리드로 정렬된 탐색 메뉴, 탭바, 세 페이지로 구성됩니다. Navbar와 Tabbar는 그 사이에 <div> 컨테이너가 있는 iframe으로 인식되며, 페이지에 세 개의 iframe이 추가로 있습니다. 그 중 하나는 항상 표시되고 탭바의 활성 선택에 종속됩니다. about:blank를 가리키는 최종 iframe은 동적으로 생성된 인앱 페이지에 사용되며, 기존 타이머를 수정하거나 새 타이머를 만드는 데 필요합니다. 이 패턴을 다중 페이지 단일 페이지 앱 (MPSPA)이라고 합니다.

앱의 HTML 구조에 대한 Chrome DevTools의 뷰. 6개의 iframe으로 구성되어 있음을 보여주는 앱.
앱은 iframe 6개로 구성됩니다.

구성요소 기반 lit-html 마크업

각 페이지의 구조는 런타임 시 동적으로 평가되는 lit-html 스캐폴드로 실현됩니다. lit-html의 배경 정보로, 효율적이고 표현력이 뛰어나며 확장 가능한 JavaScript용 HTML 템플릿 라이브러리입니다. 이를 HTML 파일에서 직접 사용함으로써 정신 프로그래밍 모델은 직접 출력 지향적입니다. 프로그래머가 최종 출력의 템플릿을 작성하면 lit-html이 데이터를 기반으로 동적으로 공백을 메우고 이벤트 리스너를 연결합니다. 앱이 Shoelace<sl-progress-ring>와 같은 서드 파티 맞춤 요소 또는 <human-duration>라는 자체 구현된 맞춤 요소를 사용합니다. 맞춤 요소에는 선언적 API (예: 진행률 링의 percentage 속성)가 있으므로 아래 목록에서 볼 수 있듯이 lit-html과 함께 잘 작동합니다.

<div>
  <button class="start" @click="${eventHandlers.start}" type="button">
    ${strings.START}
  </button>
  <button class="pause" @click="${eventHandlers.pause}" type="button">
    ${strings.PAUSE}
  </button>
  <button class="reset" @click="${eventHandlers.reset}" type="button">
    ${strings.RESET}
  </button>
</div>

<div class="progress-rings">
  <sl-progress-ring
    class="sets"
    percentage="${Math.floor(data.sets/data.activeTimer.sets*100)}"
  >
    <div class="progress-ring-caption">
      <span>${strings.SETS}</span>
      <span>${data.sets}</span>
    </div>
  </sl-progress-ring>
</div>
버튼 3개와 진행률 링이 있습니다.
위 마크업에 해당하는 페이지의 렌더링된 섹션입니다.

프로그래밍 모델

각 페이지에는 이벤트 핸들러 구현을 제공하고 각 페이지의 데이터를 제공하여 lit-html 마크업을 수명으로 채우는 상응하는 Page 클래스가 있습니다. 이 클래스는 onShow(), onHide(), onLoad(), onUnload()와 같은 수명 주기 메서드도 지원합니다. 페이지는 선택적으로 유지되는 페이지별 상태와 전역 상태를 공유하는 데 사용되는 데이터 저장소에 액세스할 수 있습니다. 모든 문자열이 중앙에서 관리되므로 국제화가 기본 제공됩니다. 앱에서 iframe 공개 상태를 전환하고 동적으로 생성된 페이지의 경우 자리표시자 iframe의 src 속성을 변경하기 때문에 브라우저에서 라우팅은 기본적으로 무료로 처리됩니다. 아래 예는 동적으로 생성된 페이지를 닫는 코드를 보여줍니다.

import Page from '../page.js';

const page = new Page({
  eventHandlers: {
    back: (e) => {
      e.preventDefault();
      window.top.history.back();
    },
  },
});
인앱 페이지가 iframe으로 인식되었습니다.
iframe에서 iframe으로 탐색이 이루어집니다.

스타일

페이지 스타일은 자체 범위가 지정된 CSS 파일에서 페이지별로 지정됩니다. 즉, 다른 페이지와 충돌할 수 없으므로 일반적으로 요소 이름으로 요소를 직접 지정할 수 있습니다. 전체 스타일이 각 페이지에 추가되므로 font-family 또는 box-sizing와 같은 중앙 설정을 반복적으로 선언할 필요가 없습니다. 여기에서 테마와 어두운 모드 옵션도 정의합니다. 아래 목록은 다양한 양식 요소를 그리드에 배치하는 환경설정 페이지의 규칙을 보여줍니다.

main {
  max-width: 600px;
}

form {
  display: grid;
  grid-template-columns: auto 1fr;
  grid-gap: 0.5rem;
  margin-block-end: 1rem;
}

label {
  text-align: end;
  grid-column: 1 / 2;
}

input,
select {
  grid-column: 2 / 3;
}
그리드 레이아웃의 양식을 보여주는 HIIT 시간 앱 환경설정 페이지
모든 페이지는 저마다의 고유한 세계입니다. 스타일 지정은 요소 이름과 직접 관련이 있습니다.

화면 wake lock

운동 중에는 화면이 꺼지면 안 됩니다. 화면을 지원하는 브라우저에서 HIIT Time은 화면 wake lock을 통해 이를 실현합니다. 아래 스니펫은 그 방법을 보여줍니다.

if ('wakeLock' in navigator) {
  const requestWakeLock = async () => {
    try {
      page.shared.wakeLock = await navigator.wakeLock.request('screen');
      page.shared.wakeLock.addEventListener('release', () => {
        // Nothing.
      });
    } catch (err) {
      console.error(`${err.name}, ${err.message}`);
    }
  };
  // Request a screen wake lock…
  await requestWakeLock();
  // …and re-request it when the page becomes visible.
  document.addEventListener('visibilitychange', async () => {
    if (
      page.shared.wakeLock !== null &&
      document.visibilityState === 'visible'
    ) {
      await requestWakeLock();
    }
  });
}

애플리케이션 테스트

HIIT Time 애플리케이션은 GitHub에서 사용할 수 있습니다. 새 창 또는 휴대기기를 시뮬레이션하는 아래의 iframe 삽입에서 바로 데모를 사용해 볼 수 있습니다.

감사의 말

이 문서는 Joe Medley, Kayce Basques, Milica Mihajlija, Alan Kent, Keith Gu가 검토했습니다.