레이블이 [007. Javascript]인 게시물을 표시합니다. 모든 게시물 표시
레이블이 [007. Javascript]인 게시물을 표시합니다. 모든 게시물 표시

2020년 3월 18일 수요일

AWS Amplify Console을 이용한 프론트엔드 배포자동화 시스템 구축하기

AWS Amplify Console을 이용한 프론트엔드 배포자동화 시스템 구축하기

이번 포스팅에서는 AWS의 Amplify Console 서비스에 대해서 정리해보려 합니다.
Amplify는 사실 3가지로 나눠집니다.
(1) Amplify 라이브러리: 클라우드 기능을 편리하게 사용할 수 있는 Javascript 라이브러리
(2) Amplify CLI: CLI 환경에서 클라우드 서비스를 생성, 관리 할 수 있는 tool
(3) Amplify Console: 정적 웹 호스팅을 위한 서버리스 지속적 배포 서비스
이 중에서 최근에 저는 Amplify Console에 대해서 알아보고 매력을 느껴서 블로그로 정리해두려합니다.


Amplify Console이란?

AWS Amplify Console에서는 Git 기반 워크플로를 통해 풀 스택 서버리스 웹 애플리케이션을 배포 및 호스팅합니다. 풀 스택 서버리스 앱은 GraphQL 또는 REST API, 파일 및 데이터 스토리지 같은 클라우드 리소스로 빌드된 백엔드와 React, Angular, Vue 또는 Gatsby 같은 단일 페이지 애플리케이션 프레임워크로 빌드된 프런트엔드로 구성되어 있습니다.
AWS Amplify Console 공식 웹사이트에 위와 같이 설명되어 있습니다. 설명대로 Amplify Console로는 프론트엔드 뿐만 아니라 백엔드까지 배포자동화 시스템을 구축할 수 있습니다.
배포자동화는 이미 잘 알려진 tool들이 있습니다. 젠킨스도 있고, AWS 내에도 CodeBuild, CodeDeploy, CodePipeline 같은 도구들이 많습니다.
이미 많은 tool들이 있음에도 Amplify Console은 왜 나왔는지를 생각해보면, 저는 그 이유가 빠르고 쉬운 배포자동화 시스템 구축에 있다고 봅니다.
아래에서 프론트엔드 프로젝트에 대해서 Amplify Console을 이용한 배포자동화 시스템을 구축해보면서, 얼마나 빠르고 쉬운지 소개하겠습니다.

Amplify Console을 이용한 프론트엔드 배포자동화 구축

이번 작업을 위해서 Next.js 프로젝트를 가져왔습니다. 사실 이번에 새로 공부해보려는건데, 어차피 공부하면서 배포도 해볼겸 Amplify Console로 해보려합니다.
Next.js를 완전 처음 셋팅한 그대로라고 보시면 됩니다.

(1) Amplify Console 접속

AWS Console에 접속해서 서비스 중에 Amplify에 들어가면 아래와 같은 화면이 나타납니다.(앱이 없을때 기준)

화면에서 'Deploy'영역에 있는 'GET STARTED'를 클릭합니다. 그러면, 앱 생성 절차를 시작하게 됩니다.

(2) Github 연결

앱 생성의 첫 단계는 소스코드 연결입니다. 아래 이미지처럼 다양한 옵션이 있습니다. 다양한 Git Repository를 선택할수도 있고, 샘플에서 선택하거나 CLI로 새로 만들수도 있습니다.
여러 옵션중에서 대부분 Git을 연결할 것이라 생각이되고, 저도 Github으로 연결하려합니다.

Github을 선택하고 'Continue'를 선택하면 Github 로그인 페이지로 이동할 것입니다. 여기서 로그인을 하면 아래 이미지와 같이 나타나고 'Authorize aws-amplify-console' 버튼을 눌러서 Amplify Console에서 사용자의 Github Repository에 접근할 수 있도록 권한을 줍니다.

(3) Git Repository 및 Branch 연결

권한을 승인하고 나면, 아래 이미지와 같이 Repositoy를 선택하는 페이지로 이동합니다.
리포지토리 선택 목록에는 제 Github 계정의 Repository들이 나타납니다.
Repository를 선택하면 바로 아래에 브랜치 선택 영역이 나타나고, 자동으로 배포하고 싶은 브랜치를 선택합니다. 다른 브랜치들도 앱생성을 완료한 이후에 더 추가 가능합니다!

(4) 빌드스펙 설정

다음으로 빌드 스펙을 설정합니다. 빌드 스펙에는 프로젝트를 어떤 명령어로 빌드하는지, 빌드 결과물은 어디에 저장되는지 지정합니다.

기본 설정되어 있는 빌드스펙은 Amplify Console에서 자동으로 프로젝트를 감지하여 작성된 것인데, 저는 아래와 같이 수정하였습니다.
빌드 설정도 나중에 수정가능 하니깐 처음부터 정확하게 입력할 필요는 없습니다.
빌드 스펙 작성이 완료되면 '다음' 버튼을 누릅니다.
version: 0.1
# 프론트엔드 프로젝트에 대한 빌드 설정 부분입니다.
frontend:
  # 빌드 단계별로 원하는 명령을 입력합니다.
  phases:
    # 빌드 전에 필요한 환경을 설치합니다.
    install:
      runtime-versions:
        nodejs: 12
    # 빌드 전에 수행할 명령을 입력합니다.
    preBuild:
      commands:
        - echo Buile Phase >> preBuild phase...
        - npm ci
    # 빌드를 수행할 명령을 입력합니다.
    build:
      commands:
        - npm run export
    # 빌드 후에 수행할 명령을 입력합니다.
    postBuild:
      commands:
        - echo Buile Phase >> Build completed on `date`
  # 빌드 결과물로 나온 아티팩트에 대한 정보를 제공합니다.
  artifacts:
    # 빌드 환경에서 빌드 출력 결과물이 생성되는 위치를 나타냅니다.
    # '**/*'는 모든 파일을 재귀적으로 나타냅니다.
    baseDirectory: out
    files:
      - '**/*'
  cache:
    paths:
      - node_modules/**/*

(5) 검토

검토단계에서는 이전에 설정한 내용들이 맞는지만 확인하고 맞으면, '저장 및 배포'를 누르면 끝입니다!
단순한 작업 몇번으로 배포자동화 시스템이 구축되는 것입니다!!



배포 확인

앱 생성이 완료 되면, 아래 이미지와 같이 브랜치별로 배포 정보가 표시됩니다.
왼쪽의 브라우저 이미지를 누르면 배포된 웹어플리케이션을 확인할 수 있는 링크가 열립니다.

이렇게 단순한 절차 몇번으로 배포자동화 시스템이 구축되었습니다!!
아주 빠르고 쉬운 방법이지 않나요? 젠킨스나 CodePipeline과 같은 tool들보다 훨씬 적은 설정으로 빠르게 배포가 된다고 생각합니다.


SPA를 Amplify Console에서 정적 웹호스팅 할 때의 주의점

Amplify Console은 정적웹호스팅을 지원하기 때문에, SPA에서 동적라우트가 있는 경우에 추가 설정을 해줘야합니다.
동적라우트는 SPA를 정적 리소스로 빌드했을 때 index.html과 같은 실제 파일로 떨어지는 것이 아니기 때문에, 동적 라우트 URL을 직접 브라우저에 입력해서 접속하게되면(또는 새탭으로 열기) 서버(e.g. Amplify Console)에서는 404에러(없는 파일)가 발생하게됩니다.
Amplify Console에서는 SPA를 올릴 경우에 ‘Rewrites and redirects’ 설정을 해줘야합니다. 아래 링크가 관련된 문서입니다.
https://docs.aws.amazon.com/amplify/latest/userguide/redirects.html#redirects-for-single-page-web-apps-spa내용을 정리하자면, 정적파일 이외의 Path는 SPA Route이기 때문에 실제로 파일이 존재하는 것이 아니라서 SPA의 Router 라이브러리가 URL을 확인하고 적절한 페이지를 표시하게 해야합니다. 그렇게 하기 위해서 Amplify Console의 Rewrites and redirects 설정에서 정적파일 이외의 Path로 요청이 들어오면 /index.html 파일을 전송하도록 지정해야합니다.


Source address: </^[^.]+$|\.(?!(css|gif|ico|jpg|js|png|txt|svg|woff|ttf|map|json)$)([^.]+$)/>
Target address: /index.html
Type: 200(Rewrite)

Amplify Console의 특징

(1) 배포 과정 간소화

Amplify Console 자체가 배포자동화 서비스이기 때문에, 당연하게 배포 과정이 매우 간소화됩니다.
Amplify Console의 앱에 연결된 Repository의 Branch에 변경이 발생하면 자동으로 이를 감지하여, 빌드와 배포를 알아서 해줍니다.

(2) 즉시 배포

Amplify Console은 배포를 위해서 내부적으로는 S3와 CloudFront를 사용합니다. CloudFront를 사용해본 사람들은 보통 여기서 질문을 가집니다.
Origin의 파일이 변경되면, CloudFront의 캐시에 저장된 것을 Invalidation해줘야 Origin에서 변경된 파일을 가져오지 않는가?
Invalidation을 해주지 않으면 캐시에 저장된 파일이 만료되어 삭제될 때까지 새로운 Origin의 새로운 파일은 적용되지 않지 않나?
일반적인 CloudFront 배포라면 그렇겠지만, Amplify Console에서는 조금 다릅니다.
Amplify Console에서는 새로운 배포를 만들어서 S3에 저장하면서 버저닝을 합니다. 그리고 CloudFront에서는 가장 최신 버전의 파일을 S3에서 가져가서 CDN에 새로 저장합니다. 그렇기 때문에, 새로운 배포가 즉각적으로 반영될 수 있습니다.


(3) 고가용성

Amplify Console은 내부적으로 S3와 CloudFront를 이용하기 때문에 가용성이 높습니다. S3만으로도 99.99%의 가용성을 가지고 있는데, 이를 CloudFront에 배포되기 때문에 다수의 저장소에 저장되어 있는 셈입니다.

(4) 간편한 SSL 인증서 적용 및 Custom Domain 설정

보통 SSL 인증서를 적용시키려면 ACM에 가서 인증서를 생성하고 CloudFront에 따로 적용을 해줘야합니다. 그리고 Custom Domain도 Route53에서 생성해줘야합니다.
하지만, Amplify Console은 SSL 인증서 생성과 Custom Domain 생성 및 적용을 바로 할 수 있습니다. 아! 물론 도메인은 Route53에 등록되어 있어야하고, Amplify Console에서는 Domain에 Record set을 만들 수 있는 것입니다.
이 작업을 실제로 해보신다면, ACM과 Route53에서 각각 작업을 안 하고 Amplify Console에서 하는게 얼마나 간편한지 느낄 수 있습니다.

(5) 작업별 테스트 배포 환경의 분리

하나의 Git Repository를 다수의 작업자가 작업을 한다면, 각자의 작업을 분리된 환경에서 배포하여 테스트 할 필요가 있을 것입니다.
Amplify Console은 Brand별로 각기 다른 배포를 관리하고 각기 다른 URL이 할당됩니다.
또한, Preview 기능을 이용하면 지정한 Branch에 Pull Request가 생성되었을 때, 자동으로 해당 Pull Request에 대한 Preview 배포를 진행합니다. 그리고, Pull Request가 타겟 Branch에 Merge되면 Preview 배포도 자동으로 삭제됩니다.
이렇게 브랜치 별로 배포 환경을 분리하거나 Pull Request별로 배포 환경을 분리함으로써, 다수의 작업자가 자신의 작업물을 독립된 환경에서 테스트 할 수 있습니다.

(6) 서버리스

여기서 소개한 모든 특징이 서버리스라서 필요할 때, 필요한 만큼 과금된다는 장점이 있습니다.
배포자동화를 위해서 상시 운영되는 서버가 필요하지 않고, 빌드 시간만큼만 과금됩니다.
그리고 웹호스팅을 위해서도 상시 운영되는 서버가 필요하지 않고, 주로 제공된 저장용량과 트래픽에 대해서 과금됩니다.


저에게는 Amplify Console이 웹 프론트엔드 프로젝트에 대한 배포자동화 서비스 중에서 아주 간편하고 강력해서 너무 매력적입니다.
물론, Amplify Console이 배포자동화를 위한 모든 기능을 제공하고 있지 않기 때문에 더 많은 기능을 위해서는 다른 방법으로 직접 배포자동화 시스템을 구축해야할 수도 있지만, 그건 향후에 필요해 질때 하면 되고 처음에는 간단하게 시작해서 점점 발전시켜나가보려 합니다!


2019년 11월 29일 금요일

[Javascript] Prototype에 대해서 알아봅니다.

[Javascript] Prototype에 대해서 알아봅니다.

Prototype(또는 Prototype Object) 이란?

자바스크립트에서 함수를 만들면 함께 생성되는 객체가 Prototype(또는 Prototype Object)입니다.
그리고 해당 함수의 'prototype'이라는 속성으로 Prototype Object와 연결됩니다.
개인적인 생각으로는 Java에서, class 내부의 static member와 유사하다고 생각합니다.

Prototype의 목적

Prototype Object는 생성자 함수에 의해 생성된 각각의 객체에 공유 프로퍼티를 제공하기 위해 사용합니다.
간단한 예시를 들면 아래와 같습니다.
function Car () {}

Car.prototype.wheel = 4;
Car.prototype.sideMirror = 2;

let smallCar  = new Car ();
let bigCar = new Car ();

console.log('smallCar :: wheel count = ', smallCar.wheel);
console.log('smallCar :: side mirror count = ', smallCar.sideMirror);
console.log('bigCar :: wheel count = ', bigCar.wheel);
console.log('bigCar :: side mirror count = ', bigCar.sideMirror);
// [ 출력 ]
// smallCar :: wheel count =  4
// smallCar :: side mirror count =  2
// bigCar :: wheel count =  4
// bigCar :: side mirror count =  2
smallCar와 bigCar는 크기가 다를 뿐 둘다 자동차입니다. 자동차이기 때문에 공통적으로 가지고 있는 속성들이 있는데, 이를 smallCar와 bigCar에 각각 만들어주기보다 Car의 Prototype Object에 만들어두면 메모리에 같은 정보를 중복으로 저장시키지 않기 때문에 메모리 효율적이며, 이런 공통적인 속성의 값을 바꿀때 모든 객체의 값을 바꾸지 않고 Prototype Object에 있는 값만 바꿔주면 되어 편리합니다.

Prototype Object에 접근하기

위의 예시를 토대로 Prototype에 접근하는 방법을 알아보면,
Car.prototype 또는 smallCar.__proto__ / bigCar.__proto__ 를 이용해서 Prototype Object에 접근할 수 있습니다.
즉, {생성자함수}.prototype 또는 {객체}.__proto__ 가 Prototype Object를 가리킵니다.

참고자료

2019년 11월 26일 화요일

[Javascript] 일반함수와 화살표 함수(arrow function)의 차이

[Javascript] 일반함수와 화살표 함수(arrow function)의 차이

일반함수와 화살표 함수(arrow function)의 차이에 대해서 알아봅니다.
ES6 이전에는 함수를 선언하기 위해서 함수선언식, 함수표현식 방식을 사용했습니다.
ES6에서는 새로운 함수 선언 방식으로 화살표 함수가 등장했습니다.
기존의 일반함수들은 function 키워드를 이용해서 함수를 선언하지만, 화살표 함수는 이름처럼 화살표 키워드를 이용합니다.
// 함수표현식
let function1 = function () {
  console.log('함수표현식');
}
// 함수선언식
function function2 () {
  console.log('함수선언식');
}

// 화살표 함수
let function3 = () => {
  console.log('화살표 함수');
}
일반함수와 화살표 함수는 크게 3가지 다른 점이 있습니다.

차이점 1: this

화살표 함수와 기존의 일반함수는 this가 다른 곳을 가리킵니다.
화살표 함수의 this는 바로 상위 스코프의 this와 같습니다. 하지만 기존의 일반함수는 this가 동적으로 바인딩됩니다.
일반함수의 this는 아래와 같습니다.
  • 내부함수, 콜백 함수: 전역 객체(브라우저에서는 window, node에서는 global)
  • 객체의 메소드: 메소드를 소유한 객체 자체
  • 생성자 함수: 생성자로 생성하는 객체

차이점 2: 생성자 함수로 사용 가능 여부

일반함수는 생성자 함수로 사용할 수 있지만, 화살표 함수는 생성자 함수로 사용할 수 없습니다.
화살표 함수는 prototype 프로퍼티를 가지고 있지 않기 때문입니다.

차이점 3: arguments 사용 가능 여부

일반함수에서는 함수가 실행될 때 암묵적으로 arguments 변수가 전달되어 사용할 수 있었지만, 화살표 함수에서는 arguments 변수가 전달되지 않습니다.
화살표 함수가 새로 나왔다고 해서 무조건 모든 상황에 좋은 건 아닌것 같습니다.
필요에 따라서 적절하게 함수를 만들어야겠습니다.

참고자료



[Javascript] var, let, const에 대해서 알아봅니다.

[Javascript] var, let, const에 대해서 알아봅니다

var, let, const는 javascript에서 변수를 선언할 때 사용하는 키워드입니다.

var

ES6 이전에는 변수를 선언할 때 var 키워드를 사용했습니다.
우선, var 키워드는 아래와 같은 특징을 가지고 있습니다.
  • 변수의 중복 선언이 가능하다.
  • var 키워드는 생략이 가능하다.
  • block-scope이 아닌 function-scope이다.
  • 호이스팅(hoisting) 당한다.
/*
 * function-scope과 block-scope의 차이
 */

// function-scope
for (var i = 0; i < 10; i++) {
  console.log(i);
}
console.log('outside i: ', i); // 출력: outside i:  10
// i를 var로 선언 했기 때문에 function-scope를 사용해서 for문에 선언한 i가 정상적으로 값을 가지고 있다.

// block-scope
for (let i = 0; i < 10; i++) {
  console.log(i);
}
console.log('outside i: ', i); // 출력: Uncaught ReferenceError: i is not defined
// i를 let으로 선언하면 block-scope을 사용해서 for문 밖에서는 사용할 수 없다.
/*
 * hoisting (호이스팅) 예시
 */

// 작성 코드
for (var i = 0; i < 10; i++) {
  console.log(i);
}

// 호이스팅 된 코드
var i
for (i = 0; i < 10; i++) {
  console.log(i);
}
위와 같은 특징을 가진 var는 변수의 사용에 대해서 다른 프로그래밍 언어와 다른 동작을 하는 이슈가 있었습니다. 잘 알고 일부러 쓰면 유용하게 사용할 수 있지만, 모르고 사용하면 스크립스 수행 간에 오류가 야기 될 수 있습니다.
오류 예 1. 한번 선언한 변수를 모르고 다시 선언 해서 다른 목적으로 사용할 때, 오류가 나지 않는다.
오류 예 2. 호이스팅으로 인해서, 변수 선언 이전에 변수를 사용하더라도 에러가 발생하지 않는다.
이로 인해서 ES6에서는 변수 선언 키워드로 새롭게 let과 const를 만들었습니다.

let

let은 아래와 같이 var와 다른 특징이 있습니다.
  • 중복 선언 불가.
  • block-scope (* const도 동일)
  • 값의 할당 이전에 선언이 반드시 되어 있어야한다.

const

var의 단점을 피하기 위해서 let 하나만 있어도 될 것 같지만, const도 그것 만의 특징이 있습니다.
  • immutable 변수를 만든다.
  • 재선언, 재할당 모두 불가.
  • 선언과 할당이 반드시 동시에 이뤄져야한다.
이로써, ES6에서는 변수의 선언에 사용하는 키워드가 여러개이므로 목적에 따라서 알맞게 사용하여야하겠습니다.

참고자료



2017년 11월 11일 토요일

[Web] Vue.js + PWA + pre-render 프로젝트 틀 잡기 (feat. AWS S3를 이용한 웹호스팅)

Vue.js + PWA + pre-render 프로젝트 틀 잡기

(feat. AWS S3를 이용한 웹호스팅)



이번 포스팅에서는 [ Vue.js + PWA + pre-render ] 조합의 웹앱을 [ AWS S3 + CloudFront ] 조합에서 웹호스팅을 할 계획으로 Vue.js 프로젝트를 준비하는 과정을 정리해보려합니다.

0. 왜 이런 조합의 프로젝트를 준비하는가?

프로젝트를 준비하기에 앞서 제 스스로도 목적을 정리하고자 왜 위와 같은 조합을 만드는지 써보려합니다.
가볍게 의식의 흐름대로 써보자면 ㅎㅎ
Vue.js로 만든 웹페이지를 만들자!
=======================> Vue.js
그런데, 앱 같은 웹을 만들어서
우리는 웹을 만들지만 사용자는 앱을 사용하는 것처럼 느끼게 하자.
=======================> PWA(Progressive Web Apps)
이렇게 웹앱을 만들어서 AWS S3에서 웹호스팅하면,
서버 비용도 줄고 가용성도 좋으니깐, AWS S3에서 웹호스팅 하자.
=======================> AWS S3
아참! PWA를 위해서는 HTTPS를 지원해야겠다!
=======================> AWS CloudFront(with AWS ACM)
아...근데 일부 소개 페이지는 SEO도 되야겠는데..
서버가 없으니 SSR이 안되겠네..
그럼 SEO를 위한 페이지만 pre rendering을 하자!
=======================> pre-render

이런 의식의 흐름으로 [ Vue.js + PWA + pre-render ] & [ AWS S3 + CloudFront ] 조합이 탄생했습니다 ㅎㅎㅎㅎ


1. 프로젝트 시작

Vue.js webpack template 중에 PWA(Progressive Web Apps)를 위한 탬플릿이 이미 존재합니다.
아래 Github에서 해당 탬플릿을 시작할 수 있습니다.
https://github.com/vuejs-templates/pwa
해당 탬플릿의 원형은 vue webpack template이기 때문에 프로젝트 구조 등에 대한 문서는 아래 링크를 확인하면 좋습니다.
https://vuejs-templates.github.io/webpack
문서의 안내에 따라서 프로젝트를 시작할 폴더에서 아래의 명령으로 탬플릿을 다운로드 받습니다.
(단, vue-cli가 사전에 설치되어 있어야합니다.)
// 탬플릿 다운로드
$ vue init pwa my-project

// 프로젝트 폴더로 이동
$ cd my-project

// 의존 패키지 설치
$ npm install

// 개발 서버 시작
$ npm run dev
탬플릿을 다운로드 받을 때 프로젝트 설정을 위한 질문이 여러개 나오는데, 전부 디폴트로 설정해도 무방하고 조금 다른 설정을 해주고 싶은 것만 선택하시면 됩니다.
여기까지만으로도 벌써 Vue.js를 이용한 PWA 웹앱의 기반이 다져졌습니다!
여기서, 딱 두개만 수정을 하겠습니다.
(1) PWA 웹앱을 만들기 위한 manifest.json 파일에서 start_url을 아래와 같이 수정해줍니다.
// 
{
  "start_url": "/",
}
기본적으로는 /index.html로 설정되어 있는데 이것을 / 로 수정합니다.
왜냐하면, 본 포스팅에서는 PWA 웹앱을 AWS S3에 업로드하여 웹호스팅을 하고 AWS CloudFront와 연결하여 https 지원을 할 예정인데,
AWS에 PWA 웹앱을 연결하는 과정에서 이미 최초 진입 파일을 index.html로 설정하기 때문에 manifest.json에서는 시작 주소를 단지 루트(/) 경로만 표시해줘야 정상작동합니다.
(2) /build/service-worker-prod.js에서 service-worker.js 파일 위치를 수정합니다.
load 이벤트 리스너를 추가하는 부분에서 sevice-worker.js를 등록하는 코드가 아래처럼 있습니다.
navigator.serviceWorker.register('service-worker.js')
기존 처럼 되어 있으면 하위 path마다 각 path에서 service-worker.js를 찾게되고 당연히 파일이 없을거라서 등록에서 오류가 납니다.
그래서 아래처럼 파일 이름 앞에 슬래쉬를 붙여서 절대주소를 명시합니다.
navigator.serviceWorker.register('/service-worker.js')



2. 프로젝트 배포

2-1. AWS S3 + CloudFront 에 웹앱 배포

저는 AWS S3에 프로젝트를 배포하고 S3의 웹호스팅 기능으로 웹앱을 사용해 보려합니다.
AWS S3로 웹호스팅 하는 방법을 아래 링크를 참고하시면 좋습니다.
https://walkinpcm.blogspot.kr/2017/06/aws-aws-s3-static-website-hosting.html
링크의 내용에서는 HTTPS를 지원하는 내용까지 있는데,
PWA를 위해서는 웹앱이 HTTPS로 제공되어야 하기 때문에 일반적인 S3 Web Hosting 문서보다 위 문서가 도움이 되리라 생각됩니다.
배포할 파일들을 만들기 위해서 프로젝트 폴더에서 아래 명령으로 배포 파일을 준비합니다.
$ npm run build
빌드를 하고나면 프로젝트 폴더의 루트 경로에 dist 폴더가 생성됩니다.
dist폴더 내부의 모든 파일들을 S3에 업로드 하면됩니다.

2-2. SPA를 위한 AWS CloudFront 추가 설정.

SPA(Single Page Application)는 URL 주소가 변경되더라도 실제 다른 파일을 불러오는게 아니라 화면 요소만 바꿔줍니다.
그런 특징이 AWS S3 + CloudFront 조합에서는 문제점 하나를 야기합니다.
SPA에서 routing으로 URL 주소를 바꾼 상태에서(ex. '/def')
새로 고침을 하면 브라우저는 그 요청을 AWS CloudFront로 보내는데
CloudFront에는 '/def'에 대한 자원이 없어서 S3로 요청하게 되고 S3도 '/def'에 대한 자원은 없어서 결국에는 에러 페이지가 반환됩니다.
이 문제는 사용자 경험도 떨어 뜨릴 뿐 아니라 웹크롤러가 페이지를 읽지 못하는 문제이기도 합니다.
그래서 CloudFront의 에러페이지 설정에서 403, 404 에러가 발생하면 root path로 이동하도록 설정해줍니다.
설정 방법은 아래와 같습니다.
CloudFront에서 설정할 배포를 선택하고 Error Pages탭을 선탁합니다.
그리고 Create Custom Error Response를 선택합니다.

HTTP Error Code는 어떤 에러코드에 대해서 Error 처리를 할지 선택하는 것입니다.
403, 404 2개에 대해서 각각 추가해주셔야합니다.
Customize Error Response를 Yes로 선택하고,
Response Page Path에 /index.html을 기입합니다.
HTTP Response Code는 200: OK로 입력합니다.

에러코드 403, 404 대해서 위와같이 설정을 마치면 아래 처럼 에러 처리 항목 2개가 생겼을겁니다.

2-3. PWA 웹앱 확인

프로젝트 배포 파일들을 AWS S3에 업로드 하고난 뒤에 (HTTPS 까지 지원하게 한 뒤에), PWA 웹앱이라면 모바일 크롬에서 해당 페이지에 접속했을 때 하단에 홈 화면에 설치하겠냐는 배너가 나타나야 정상입니다.
하지만 설치 배너는 유저가 5분 동안 2번 방문해야 나타나는 조건이 있습니다.
개발과정에서는 그러한 조건을 충족시키기가 번거로우므로 웹앱에 브라우저로 접속했을 때 설치배너가 무조건 나타나게 해주는 설정을 합니다.
모바일 크롬에서 아래 주소를 주소창에 입력합니다.
chrome://flags/#bypass-app-banner-engagement-checks
그리고 해당 항목(bypass app banner engagement checks)를 사용으로 변경합니다.
변경하면 크롬을 다시 시작한다고 합니다. 다시 시작하고 다시 웹앱에 접속하면 설치배너가 나타납니다.
물론 설치배너를 통해서 설치 하지 않고, 크롬 메뉴에서 '홈 화면에 추가' 기능을 이용해도 똑같이 PWA 웹앱이 스마트폰에 설치되듯이 추가됩니다.


3. Pre render 플러그인 사용하기

위에서도 언급했듯이 Vue.js PWA 탬플릿은 원형이 Vue.js webpack 탬플릿이기 때문에 Vue.js webpack의 문서를 참고하면됩니다.
그리고 고맙게도 그 문서에는 Pre render에 대한 내용도 있습니다.
Vue.js에서 Pre render를 할 때는 prerender-spa-plugin를 추천합니다. Vue.js에서 공식적으로 추천하고 있습니다.
(문서: https://vuejs-templates.github.io/webpack/prerender.html)
(Github: https://github.com/chrisvfritz/prerender-spa-plugin )
사용방법은 무척 간단합니다.
(1) prerender-spa-plugin 설치
npm i prerender-spa-plugin --save-dev
(2) webpack.conf.js에 플러그인 설정
Vue.js PWA 탬플릿을 사용했다면 /build/webpack.prod.conf.js에 아래 코드들을 추가합니다.
먼저, 아래 require 문을 다른 어떤 require(또는 import)들 보다 상위에 작성합니다.
제일 상위에 위치하지 않으면 페이지가 정상적으로 표시되지 않습니다.
var PrerenderSpaPlugin = require('prerender-spa-plugin')
그리고, 아래 코드를 plugins 배열에 추가합니다.
new PrerenderSpaPlugin(
  // 컴파일된 파일들이 위치하는 폴더를 명시합니다.
  path.join(__dirname, '../dist'),
  // pre render를 할 path를 지정합니다. 콤마로 연결해서 여러 path를 기입할 수 있습니다.
  [ '/', '/abc' ]
)
(3) vue-router 의 mode를 history로 변경
prerender-spa-plugin을 사용하려면 router의 mode가 반드시 history여야합니다.
그러므로 아래와 같이 vue router의 mode를 history로 설정합니다.
const router = new VueRouter({
  mode: 'history',
  routes: [...]
})
Vue.js PWA 탬플릿을 사용한다면, /src/router/index.js에 mode를 추가하면 됩니다.
아래는 탬플릿의 원형에 mode만 추가한 것입니다.
import Vue from 'vue'
import Router from 'vue-router'
import Hello from '@/components/Hello'

Vue.use(Router)

export default new Router({
  mode: 'history',
  routes: [
    {
      path: '/',
      name: 'Hello',
      component: Hello
    }
  ]
})



여기까지 전부 하셨다면 Vue.js + PWA + pre render 조합의 웹앱의 기반을 잡으셨다고 할 수 있습니다.
그리고 그 웹앱을 AWS S3 + CloudFront를 이용해서 웹서버 없이 저렴하고 가용성 높게 배포 하게 되셨습니다.
혹시 참고하실 수 있으실까해서 이 포스팅을 준비하면서 연습해본 프로젝트 소스를 Github에 올려두었습니다.
아래 링크에서 참고하시면 도움이 되리라 생각됩니다.
(Github Repository 링크 : https://github.com/ChanMinPark/vue-pwa-prerender-s3-cloudfront )


이번 포스팅은 여기서 마치겠습니다.
혹여 내용이 틀리거나 수정 보완 해야하는 부분이 있다면 댓글로 남겨주세요.
감사히 받아들이고 수정, 보완하겠습니다.
감사합니다.


참고링크