Missed the action at the 2018 Chrome Dev Summit? Catch up with our playlist on the Google Chrome Developers channel on YouTube. Watch now.

PRPL 패턴

모바일 웹은 너무 느립니다. 지난 몇 년 동안 웹은 문서 중심 플랫폼에서 최고급 애플리케이션 플랫폼으로 진화해 왔습니다. 플랫폼 자체의 발전(예: 서비스 워커)과 앱 빌드에 사용되는 도구와 기술의 발전 덕분에, 사용자는 네이티브 앱에서 수행할 수 있는 거의 모든 작업을 앱에서도 수행할 수 있습니다.

이와 동시에, 상당수의 컴퓨터 시스템은 성능이 강력하고 네트워크 연결이 빠르고 안정적인 데스크톱 시스템으로부터 비교적 성능이 떨어지고 연결이 느리고 불안정한 휴대기기로 바뀌었습니다. 이러한 현상은 수많은 사용자들이 온라인으로 이동하고 있는 세상에서 특히 그러합니다.

불행히도, 우리가 데스크톱 시절에 다양한 기능의 강력한 웹 앱을 빌드하고 배포하기 위해 만들었던 패턴은 일반적으로 휴대기기에서는 로드 시간이 너무 오래 걸립니다. 너무 길어서 사용자들이 쉽게 포기해 버립니다.

이 때문에, 최신 웹 플랫폼 기능들을 활용하여 모바일 웹 환경을 보다 신속하게 제공할 수 있는 새로운 패턴을 만들 필요성이 부각되었습니다.

PRPL 패턴

PRPL은 PWA(Progressive Web App)를 구성하고 제공하기 위한 패턴이며 앱 전달 및 출시의 성능에 중점을 둡니다. PRPL은 다음의 약자입니다.

  • Push: 초기 URL 경로에서 중요한 리소스를 푸시합니다.
  • Render: 초기 경로를 렌더링합니다.
  • Pre-cache: 남은 경로를 사전 캐시합니다.
  • Lazy-load: 필요 시 남은 경로를 지연 로드하고 생성합니다.

PRPL은 PWA의 기본 목표와 표준을 추구할 뿐만 아니라 다음과 같은 경우에 맞게 최적화를 수행합니다.

  • 최소 상호작용 시간(Time-to-Interactive)
    • 특히 최초 사용 시(진입점과 무관)
    • 특히 실제 휴대기기에서
  • 최대한의 캐싱 효율성(특히 업데이트가 릴리스되는 동안)
  • 개발 및 배포의 단순성

PRPL 패턴은 최신 웹 플랫폼 기능들을 모아 놓은 것이지만, 모든 기능을 사용하지 않고도 이 패턴을 적용할 수 있습니다.

실제로, PRPL은 구체적인 기술이나 기법이 아니라 모바일 웹의 성능을 개선하려는 마음가짐이나 장기적 비전에 가깝습니다. PRPL 이면의 아이디어는 새로운 것이 아니며, Polymer 팀이 그 틀을 짜고 명명한 후 Google I/O 2016에 공개했습니다.

Polymer Shop 전자상거래 데모는 PRPL을 사용하여 리소스를 정밀하게 제공하는 애플리케이션의 가장 좋은 예시입니다. 이 데모는 실제 휴대기기에서 각 경로의 상호작용을 놀라운 속도로 실현합니다.

1.75초만에 상호작용이 되는 Polymer Shop 데모

대부분의 실제 프로젝트에서 PRPL 비전을 완전한 형태로 실현하기는 솔직히 말해 너무 이릅니다. 그러나 그러한 마음가짐을 갖거나 다양한 관점에서 비전을 추구하는 것은 절대로 너무 이른 것이 아닙니다. 오늘날 PRPL를 추구하기 위해 앱 개발자, 도구 개발자 및 브라우저 공급업체가 따를 수 있는 유용한 단계들이 많이 있습니다.

앱 구조

다음과 같은 구조의 단일 페이지 앱(SPA)이 있는 경우 PRPL이 효과가 있을 것입니다.

  • 모든 유효 경로로부터 애플리케이션의 주요 진입점 이 제공되는 경우. 이 파일은 다른 URL로부터 제공되며 여러 번 캐시되므로 매우 작아야 합니다. 최상위가 아닌 URL로부터 제공될 수도 있으므로, 진입점의 모든 리소스 URL은 절대 URL이 되어야 합니다.

  • 최상위 앱 로직, 라우터 등이 포함된 또는 앱 셸.

  • 지연 로딩되는 앱 프래그먼트. 프래그먼트는 지연 로드되는 특정 뷰의 코드나 기타 코드를 나타낼 수 있습니다. 예를 들어, 기본 앱 중에서 첫 페인트에 필요없는 부분(예: 메뉴)은 사용자가 앱과 상호작용할 때까지 표시되지 않습니다. 셸은 필요할 때 프래그먼트를 동적으로 가져오는 역할을 합니다.

서버와 서비스 워커가 함께 작동하여 비활성 경로의 리소스를 사전 캐시합니다.

사용자가 경로를 전환하면 앱은 아직 캐시되지 않은 모든 필수 리소스를 지연 로드하고, 필요한 뷰를 생성합니다. 반복적인 경로 방문은 즉시 상호작용이 되어야 합니다. 여기서는 서비스 워커가 많은 도움이 됩니다.

아래 다이어그램은 웹 구성 요소를 사용하여 구성 가능한 간단한 앱의 구성 요소를 보여줍니다.

뷰가 두 개 있는 앱의 다이어그램, 두 개의 뷰는 개별 및 공유
종속성이 있음

참고: HTML 가져오기는 Polymer가 선호하는 번들링 전략이지만, 여러분은 코드 분할 및 경로 기반 청크를 사용하여 최신 자바스크립트 모듈 번들러에서 유사한 설정을 실현할 수 있습니다.

이 다이어그램에서 실선은 정적 종속성_을 나타내며 외부 리소스는 파일에서 <link><script> 태그를 사용하여 식별됩니다. 점선은 _동적 또는 필요 시 로드되는 종속성 을 나타내며 셸에 필요할 때마다 파일이 로드됩니다.

빌드 프로세스는 이 모든 종속성의 그래프를 빌드하며 서버는 이 정보를 사용하여 파일을 효율적으로 제공합니다. HTTP/2를 지원하지 않는 브라우저의 경우 이 프로세스는 가공된 번들 세트도 빌드합니다.

앱 진입점

이 진입점은 셸을 가져와서 인스턴스화할 뿐만 아니라 필요한 폴리필을 조건부로 로드해야 합니다.

진입점의 주요 고려사항은 다음과 같습니다.

  • 최소한의 정적 종속성(즉 앱 셸 자체를 넘어서지 않음)
  • 필요한 폴리필을 조건부로 로드
  • 모든 종속성에 절대 경로를 사용

앱 셸

이 셸은 라우팅을 담당하며 일반적으로 앱의 주요 탐색 UI를 포함합니다.

앱은 필요할 때 프래그먼트를 지연 로드해야 합니다. 예를 들어, 사용자가 새 경로로 변경하면 앱은 이 경로에 관련된 프래그먼트를 가져옵니다. 이 때 새 요청을 서버에 시작할 수도 있고 그냥 캐시에서 리소스를 로드할 수도 있습니다.

셸(정적 종속성 포함)에는 첫 페인트에 필요한 모든 것이 포함되어야 합니다.

빌드 출력

빌드 프로세스는 아래와 같은 두 가지 빌드를 생성할 수 있으며, 이것은 PRPL 사용 시에 그다지 어려운 요구사항은 아닙니다.

  • 번들되지 않은 빌드는 서버/브라우저 조합을 위해 고안되었으며, 캐싱을 최적화하면서도 신속한 첫 페인트를 위해 브라우저에 필요한 리소스를 전달하도록 HTTP/2를 지원합니다. <link rel="preload"> 또는 HTTP/2 Push를 사용하여 이러한 리소스 전달을 효율적으로 트리거할 수 있습니다.

  • 번들된 빌드는 서버 푸시를 지원하지 않는 서버/브라우저 조합에서 애플리케이션을 실행하는 데 필요한 왕복 횟수를 최소화하도록 고안되었습니다.

여러분의 서버 로직은 각 브라우저에 적합한 빌드를 전달해야 합니다.

번들된 빌드

HTTP/2를 처리하지 않는 브라우저의 경우 빌드 프로세스는 다른 번들 세트를 생성할 수 있습니다. 하나는 셸용 번들이고 다른 하나는 각 프래그먼트용 번들입니다. 아래 다이어그램은 웹 구성 요소를 다시 사용하여 간단한 앱을 번들하는 방법을 보여줍니다.

이전과 동일한 앱의 다이어그램, 이 경우 번들된 종속성이
 세 개 있음

둘 이상의 프래그먼트에 의해 공유되는 모든 종속성은 셸과 그 정적 종속성이 번들됩니다.

각 프래그먼트와 해당 미공유 정적 종속성은 단일 번들로 구성됩니다. 서버는 브라우저에 따라 적절한 버전(번들되거나 번들되지 않은 버전)의 프래그먼트를 반환해야 합니다. 즉, 번들 여부를 몰라도 셸 코드가 detail-view.html을 지연 로드할 수 있습니다. 셸 코드는 서버와 브라우저에 의존하여 가장 효율적인 방식으로 종속성을 로드합니다.

배경: HTTP/2 및 HTTP/2 서버 푸시

HTTP/2에서는 단일 연결을 통해 다중화된 다운로드를 허용하므로, 여러 개의 작은 파일을 보다 효율적으로 다운로드할 수 있습니다.

HTTP/2 서버 푸시에서는 서버가 리소스를 브라우저에 우선적으로 전송하도록 허용합니다.

HTTP/2 서버 푸시가 다운로드 속도를 어떻게 높이는지 설명하기 위해, 링크된 스타일시트가 있는 HTML 파일을 브라우저가 검색하는 방법을 예로 들어 보겠습니다.

HTTP/1에서:

  • 브라우저가 HTML 파일을 요청합니다.
  • 서버가 HTML 파일을 반환하고 브라우저가 파일 분석을 시작합니다.
  • 브라우저가 <link rel="stylesheet"> 태그를 만나고 새로운 스타일시트 요청을 시작합니다.
  • 브라우저가 스타일시트를 수신합니다.

HTTP/2 푸시에서:

  • 브라우저가 HTML 파일을 요청합니다.
  • 서버가 HTML 파일을 반환하고 이와 동시에 스타일시트를 푸시합니다.
  • 브라우저가 HTML 분석을 시작합니다. 브라우저가 `을 만날 때쯤이면 이미 스타일시트가 캐시에 있습니다.

가장 단순한 경우에 HTTP/2 서버 푸시는 단일 HTTP 요청-응답을 제거합니다.

HTTP/1에서 개발자는 페이지 렌더링에 필요한 HTTP 요청 수를 줄이기 위해 리소스를 번들합니다. 그러나 번들링은 브라우저 캐시의 효율성을 떨어뜨릴 수 있습니다. 각 페이지의 리소스가 단일 번들로 결합된 경우 각 페이지는 자체 번들을 가지며 브라우저는 공유 리소스를 식별할 수 없습니다.

HTTP/2와 HTTP/2 서버 푸시의 조합은 실제 번들링이 없이도 번들링의 _이점_을 제공합니다(짧은 지연 시간). 리소스를 별도로 유지한다는 것은 효율적인 캐싱이 가능하고 페이지 간에 공유가 가능하다는 의미입니다.

HTTP/2 푸시는 브라우저의 로컬 캐시에 파일이 이미 있거나 대역폭이 이미 포화 상태이더라도 강제로 데이터를 브라우저에 보내므로, 사용 시 주의가 필요합니다. 잘못 수행할 경우 성능이 저하될 수 있습니다. <link rel="preload">는 요청의 우선순위를 브라우저가 정확하게 결정하도록 도와줄 수 있습니다.

결론

경로 코드를 보다 정밀하게 로드하고 브라우저가 작업을 더 효과적으로 예약할 수 있게 되면 애플리케이션에서 더욱 신속한 상호작용이 가능할 것입니다. 우리는 신속한 상호작용이 가능한 더 나은 아키텍처가 필요합니다. 이러한 목표를 실제 휴대기기에서 실현하기 위한 방법을 보여주는 예가 바로 PRPL 패턴입니다.

입력 이벤트가 발송되는 것을 막는 스크립트로 인해 링크 누르기가 수초간 지연되는 경우, 이는 성능 향상을 위한 조치가 필요함을 나타냅니다. 이러한 문제는 갈수록 커지는 자바스크립트 라이브러리를 사용하여 빌드된 애플리케이션에서 공통적으로 나타나며, 이 경우 렌더링된 UI가 제대로 작동하지 않습니다.

PRPL은 사용자가 상호작용할 수 있는 경로를 만드는 데 필요한 최소한의 기능 코드를 제공하여 이러한 문제를 해결할 수 있도록 지원합니다.