Home Blogs Layer0이 React PWA에서 AMP를 자동으로 생성하는 방법
Applications

Layer0이 React PWA에서 AMP를 자동으로 생성하는 방법

About The Author

Outline

AMPConf 2019는 이제 막 시작되었습니다! 이 블로그 게시물 시리즈에서는 React Storefront 프레임워크와 Layer0을 통해 개발자가 React 앱에서 AMP를 보다 쉽게 지원할 수 있는 방법을 강조함으로써 AMPConf를 축하합니다.

암페어를 건조하게 유지

Microsoft는 점진적 웹 애플리케이션(PWA)과 AMP(Accelerated Mobile Pages)를 모두 이커머스 부문에서 비교적 일찍 도입했습니다. React 기반 PWA를 통해 개발자는 네이티브 앱과 경쟁하는 웹에서 몰입도 높은 경험을 제공할 수 있습니다. 그러나 검색 생성 트래픽에 관해서는 AMP가 가능한 가장 빠른 옵션을 제공합니다.

실제로 Google의 권장 고객 여정은 먼저 AMP 버전의 앱을 제공하여 사용자를 검색하고 이후 페이지에서 사이트의 전체 PWA 버전으로 전환하는 것입니다. 유통업체 웹사이트 트래픽의 거의 절반이 유기적 검색에서 발생하기 때문에 AMP와 PWA를 모두 지원하는 것이 최우선 과제가 되었습니다.

불행히도 PWA와 AMP 기술은 이보다 더 다양할 수 없습니다. PWA는 React, Vue, Angular와 같은 최신 라이브러리를 사용하며, 여기서 JavaScript는 HTML과 CSS를 렌더링하고 상호 작용을 제공하는 중심 역할을 수행합니다. 반면에 AMP 페이지는 자바스크립트를 사용하는 것이 완전히 금지되어 있으며 CSS와 HTML 모두에 엄격한 제한이 있습니다. 그 결과 개발자는 AMP와 PWA를 모두 지원하기 위해 일반적으로 AMP에서 앱의 상당 부분을 다시 코딩해야 합니다. 그리고 개발 팀의 부담은 거기서 끝나지 않습니다. 모든 버그 수정, 레이아웃 변경, 새로운 기능 등은 AMP 및 PWA 코드베이스 모두에 전파되어야 할 수 있습니다.

좋은 앱을 한 번 만드는 것은 충분히 어렵습니다. 아무도 같은 앱을 두 번 쓰고 싶지 않습니다. 개발자들은 이런 종류의 것을 너무 싫어해서 인기있는 약어 인 DRY (Don’t Repeat Yourself). 개발자로서, 우리는 이커머스 PWA를 위해 만든 React 프레임워크에 자동 AMP 지원을 추가하는 데 일찍부터 투자했습니다. 이렇게 하면 개발자는 React에서 프로그레시브 웹 앱을 작성하고 추가 개발 노력 없이 AMP 지원을 받을 수 있습니다.

그리고 그것은 우리의 고객을 위해 아주 잘 작동했습니다. React Storefront와 함께 AMP를 구현하는 데는 일반적으로 고객이 하루나 이틀 정도 걸리며 대부분의 경우 모든 것이 예상대로 작동하는지 확인하는 것입니다.

이 게시물에서는 React Storefront가 단일 코드베이스에서 AMP 및 PWA를 지원하는 데 얼마나 많은 노력을 기울이는지 다룰 것입니다. 다음 장에서는 복잡한 엔터프라이즈 환경에서 AMP를 제공하는 데 도움이 되는 Layer0의 흥미로운 새 기능을 소개합니다.

왜 모든 React 프레임워크가 그렇게 하지 않을까요?

일반적인 React 앱의 경우 AMP 콘텐츠를 자동으로 추출하기가 어렵습니다. 대부분의 React 앱은 브라우저에서만 실행되도록 설계되었지만 AMP 콘텐츠는 브라우저에 도달하기 전에 React를 포함한 JavaScript를 포함할 수 없기 때문입니다. 즉, Google AMP Cache를 브라우저에 보내는 것과 동일한 React 코드로 가리킬 수는 없습니다. 그들은 완전히 다른 형식입니다.

이러한 한계를 극복하기 위해 초기 아키텍처에서 React Storefront 앱을 기본적으로 보편적으로(isomorphic이라고도 함) 구현하고 Layer0에서 SSR(Server-Side Rendering)을 지원하기로 결정했습니다. SSR을 사용하면 페이지가 사용자에게 제공되기 전에 서버에서 렌더링이 수행됩니다. SSR 추가의 주요 목표는 성능과 SEO를 향상시키는 것이었지만, 서버에서 React Storefront 앱을 실행한 다음 아래 기술과 함께 HTML 출력을 유효한 AMP HTML로 자동 변환할 수 있었습니다.

AMP가 지원됨을 Google에 알립니다.

AMP를 구현하기 위한 첫 번째 단계는 Google 크롤러에게 AMP에 해당하는 페이지가 존재함을 알리는 것입니다. 일반적으로 페이지의 AMP 버전을 별도로 만든 다음 AMP 및 PWA 콘텐츠를 서로 다른 URL에서 모두 제공하도록 응용 프로그램의 라우터를 구성해야 합니다. React Storefront를 사용하면 최상위 페이지 구성 요소에 @withAmp 데코레이터를 추가하기만 하면 됩니다. React Storefront는 URL에 “.amp”를 추가하기만 하면 모든 페이지에 대해 유효한 AMPHTML을 자동으로 렌더링합니다. @withAmp 데코레이터는 이 규칙을 활용하여 문서 헤드에 필요한 링크 태그를 추가합니다.

즉, 다음과 같습니다.

				
					@withAmp
class Product extends Component {
  ...
}
				
			

PWA 페이지에 다음과 같은 결과가 나타납니다.

				
					<link rel="amphtml" href="https://www.mysite.com/p/1.amp"/>
				
			

Google의 크롤러가 /p/1에 대한 링크를 볼 때 AMP 콘텐츠를 다운로드하여 Google의 AMP CDN에서 직접 제공합니다.

적절한 SEO를 위해 AMP 페이지는 rel=canonical 태그를 페이지의 원래 PWA 버전에 다음과 같이 포함시켜야 합니다.

				
					<link rel="canonical" href="https://www.mysite.com/p/1"/>
				
			

AMP 페이지와 비 AMP 페이지가 적절한(그러나 다른 버전의) <링크> 태그를 사용하여 서로 다시 가리키는 것이 중요하다는 점을 강조할 필요가 있습니다. 이러한 설정이 제대로 없으면 Google은 AMP 콘텐츠를 제공하지 않으며, 더 나쁜 경우 AMP 페이지가 비 AMP 페이지의 SEO 순위를 식인 화 할 수 있습니다. React Storefront는 당신을 위해 모든 “AMP 이중 입력 부기”를 수행하므로 누군가가 올바른 태그를 업데이트하는 것을 잊어 버렸기 때문에이 일에 대해 걱정할 필요가 없습니다.

AMP 인식 구성 요소

AMP에서 가장 기본적인 상호 작용을 구현하는 것은 큰 고통이 될 수 있습니다. 예를 들어 AMP의 간단한 수량 필드는 다음과 같습니다.

				
					<amp-form>
<amp-state id="product">
<script type="application/json">
      {
        "id": "123",
        "name": "Product",
        "quantity": 1
      }
</script>
</amp-state>
<input
    type="text"
    [value]="product.quantity"
    on="input-throttled:AMP.setState({ product: { quantity: event.value } })"
  />
</amp-form>
				
			

점진적 웹 앱의 모든 대화형 컨트롤에 대해 이와 같은 두 가지 버전의 코드를 작성한다고 상상해보십시오. 출시 기한이 다가옵니다!

다행히도, 우리는 당신을 위해 열심히 일했습니다. React Storefront는 QuantitySelector와 같은 거친 AMP 인식 컴포넌트를 제공하여 이러한 모든 디테일을 숨깁니다. React Storefront에서는 다음과 같이 간단하게 사용할 수 있습니다.

				
					<QuantitySelector product={product}/>
				
			

React 프레임워크는 Google이 AMP 페이지를 요청할 때 컴포넌트의 AMP 버전을 렌더링합니다.

조건부 렌더링

대부분의 경우 개발자는 React Storefront 프레임워크 내의 AMP 인식 구성 요소 중 하나를 사용하여 AMP에서 상호 작용을 제공할 수 있습니다. 그러나 AMP에 대해 특정 항목을 렌더링해야 하는 경우 프레임워크는 AMP에서 특정 콘텐츠를 조건부로 렌더링하는 데 사용할 수 있는 앱 상태의 부울 amp 필드를 노출합니다.

예를 들면 다음과 같습니다.

				
					import React, { Component } from 'react'
import { inject } from 'mobx-react'
@inject('app')
class MyAMPAwareComponent extends Component {
  render() {
    if (this.props.app.amp) {
      return (
        // AMP content
      )
    } else {
      return (
        // PWA content
      )
    }
  }
}
				
			

범용 분석

상호작용 이벤트를 정의하는 AMP의 선언적 방법은 React와 완전히 다릅니다. 예를 들어 이벤트를 Google Analytics로 전송하여 특정 제품 링크의 클릭을 추적하려는 경우를 가정해 보겠습니다. AMP에서는 다음과 같습니다.

				
					<amp-analytics type="googleanalytics">
<script type="application/json">
    {
      "triggers": [
        {
          "on":"click",
          "event":"product_clicked",
          "selector":"#product1",
          "request":"event",
          "productID": "1"
        }
      ]
    }
</script>
</amp-analytics>
<a id="product1" href="/p/1" alt="Red Shirt">
<amp-img src="/images/products/1" height="100" width="100"/>
<div>Red Shirt</div>
</a>
				
			

React 구현은 아끼지 않겠지만, onClick 리스너와 ga()에 대한 몇 가지 호출이 포함될 가능성이 높습니다. 두 사람이 똑같이 보이지 않을 것이라고 말하면 충분합니다.

React Storefront는 추상화인 Track 구성 요소를 제공하여 다음 두 가지를 모두 구현합니다.

				
					<Track event="product_clicked" productID={product.id}>
<a href="/p/1" alt="Red Shirt">
<Image src="/images/products/1"/>
<div>Red Shirt</div>
</a>
</Track>
				
			

서버 렌더링 HTML을 AMPHTML로 변환

위의 전략은 유효한 AMP를 렌더링하는 방법의 약 80 %를 얻습니다. 그러나 문서에 추가 변경이 필요합니다. React Storefront는 보내는 HTML을 전송하기 전에 변환하여 다음과 같은 몇 가지 변경 사항을 적용합니다.

앰프 상용구 추가 및 ⚡

AMP는 문서에 몇 가지 특정 요소가 있어야 합니다. 여기에는⚡ 루트 HTML 요소의 ” “” 특성과 AMP 상용구라는 표준 스타일 요소가 포함됩니다.

				
					<style amp-boilerplate>body{-webkit-animation:-amp-start 8s steps(1,end) 0s 1 normal
				
			

CSS 변환 및 통합

AMP는 모든 CSS가 단일 스타일 요소의 본문에 제공되어야 합니다. style 속성 및 <링크 rel=”stylesheet” 사용은 > 금지됩니다. React Storefront는 코드베이스 전체의 모든 스타일을 여러 <스타일> 요소 또는 인라인 스타일 속성에 내장하여 하나의 <스타일 앰프 사용자 지정 요소로 통합합니다.> React Storefront는 스타일 특성을 사용할 때마다 해당 규칙이 포함된 고유한 CSS 클래스를 만들고 클래스를 요소에 적용하고 style 속성을 제거한 다음 amp-custom 스타일 요소에 클래스를 추가합니다. 즉, 다음과 같습니다.

				
					<div style="font-weight:bold">Red Shirt</div>
				
			

다음과 같이 됩니다.

				
					<style amp-custom>
  …
  .mi1 {
    font-weight:bold;
  }
</style>
<div class="mi1">Red Shirt</div>
				
			

모든 스타일에 걸쳐 추가되면 CSS의 자동 변환이 React 앱에서 AMP 호환 페이지를 작성할 때 또 다른 주요 골칫거리를 없애줍니다.

마크업 정리 중

AMP가 마크업에 적용하는 다양한 규칙이 있습니다. 예를 들어, ReactDOM이 부울 특성을 렌더링하는 방식은 잘못된 AMPHTML을 생성합니다. 이 JSX:

				
					<script
  async
  custom-element="amp-sidebar"
  src="https://cdn.ampproject.org/v0/amp-sidebar-0.1.js"
/>
				
			

이 HTML이 생성됩니다.

				
					<script
  async
  custom-element="amp-sidebar"
  src="https://cdn.ampproject.org/v0/amp-sidebar-0.1.js"
/>
				
			

AMP 유효성 검사기에서 다음과 같은 오류를 표시합니다.

Crux는 PWA/SPA의 ‘전화’ 트래픽 공유를 추적할 수 없습니다.

컴포넌트 라이브러리를 사용하는 경우 컴포넌트에 의해 렌더링된 HTML 중 일부가 여러 가지 이유로 AMP 유효성 검사기에서 실행될 수 있습니다. React Storefront는 널리 사용되는 Material UI 라이브러리의 사용을 권장하며 생성되는 HTML을 정리하기 위한 특정 규칙을 제공합니다. 이것은 상태 관리에서 구성 요소 및 스타일링에 이르기까지 모든 것을 포괄하는 포괄적 인 React 프로그레시브 웹 앱 프레임워크를 사용하는 것이 개발자 속도 증가라는 측면에서 그 가치를 보여줍니다.

AMP 및 PWA를 위한 인프라

AMP 및 PWA를 구현하는 개발자는 앱의 두 가지 버전을 구현한 다음 향후 변경 사항(즉, 모든 수정 사항이 두 곳에서 코드 변경이 됨)을 통해 유지하거나 자동화를 사용하여 페이지에서 AMP 콘텐츠를 파생시킬 수 있습니다. Layer0에서 우리는 후자를 선택했는데, 이는 고객에게 매우 효과적이었습니다. 지금까지 설명한 React Storefront 기능은 이러한 성공의 이유 중 일부일 뿐입니다. 다음 강의에서는 이 프레임워크가 Layer0(Edgio)과 통합되어 엔터프라이즈 환경에서 AMP를 지원하는 방법에 대해 알아보겠습니다. 계속 지켜봐 주세요.