Netlify Forms 및 Edge를 사용하여 Angular 양식 구축 및 배포

게시 됨: 2022-03-10
빠른 요약 ↬ Netlify Forms는 HTML 양식에서 제출물을 자동으로 수신하는 양식 처리 기능입니다. 이 기사에서는 Angular 반응 형식과 함께 사용하는 방법과 Netlify의 호스팅 플랫폼인 Netlify Edge에 완성된 앱을 배포하는 방법을 다룹니다.

앱의 프론트엔드, 백엔드 및 배포 워크플로를 만드는 데는 많은 작업이 필요합니다. 앱이 사용자로부터 제한된 양의 데이터 제출만 수집하는 경우 전체 백엔드를 구축하는 것은 시간과 노력의 가치가 없어 보일 수 있습니다. 완전한 백엔드 개발에 대한 대안은 Netlify Forms를 사용하는 것입니다. 이 자습서에서는 Netlify Forms와 함께 Angular 반응 양식을 사용하는 방법을 설명합니다. Netlify Forms는 Netlify에 배포될 때만 작동하므로 Netlify Edge에 앱을 배포하는 방법도 설명하겠습니다.

툴킷

Angular 반응 형식은 ReactiveFormsModule 공급자를 사용하여 구성 요소 클래스 내에서 명시적으로 생성된 구조화된 데이터 모델이 있는 형식입니다. 양식 보기 내의 각 입력 요소에 대해 양식 모델이 작성됩니다. 이 양식 모델은 FormControl 클래스의 인스턴스이며 양식 요소의 값을 추적합니다. 모델이 변경될 때마다 FormControl 인스턴스가 이전 모델을 업데이트하는 대신 새 데이터 모델을 반환하기 때문에 양식 모델은 변경할 수 없습니다. 불변성은 변경 감지를 보다 효율적으로 만들고 관찰 가능한 연산자로 데이터를 변경할 수 있습니다. 양식 입력 요소는 양식 모델에 직접 연결되기 때문에 이들 간의 업데이트는 동기식이며 UI 렌더링에 의존하지 않습니다.

Netlify는 다양한 기술로 구축된 사이트를 구축, 배포 및 호스팅할 수 있는 플랫폼입니다. Angular로 구축된 사이트는 Netlify에서 호스팅할 수 있습니다. Netlify는 이러한 사이트의 빌드 및 배포를 단순화, 자동화 및 보강하는 다양한 도구를 추가로 제공합니다. 이 튜토리얼에서는 Netlify Edge와 Netlify Forms라는 두 가지 제품을 사용할 것입니다.

앞에서 설명한 것처럼 Netlify Forms는 HTML 양식에서 제출물을 자동으로 수신하는 양식 처리 기능입니다. API, 스크립트 등과 같은 제출 처리 구성이 필요하지 않습니다. 이 기능은 Netlify에 배포된 사이트의 양식에서만 작동합니다. 기본적으로 활성화되어 양식 제출을 설정하는 데 필요한 구성을 더욱 줄여줍니다. 제출 처리는 Netlify의 빌드 봇이 사이트의 HTML 파일을 구문 분석하는 배포 중에 설정됩니다.

Netlify Edge는 사이트와 애플리케이션이 게시되는 글로벌 애플리케이션 제공 네트워크입니다. A/B 테스트, 롤백, 스테이징 및 단계적 롤아웃과 같은 기능을 제공합니다. Netlify Edge의 모든 배포는 원자적입니다. 즉, 모든 파일이 업로드/업데이트되고 사이트에 대한 변경 사항이 준비된 경우에만 사이트가 활성화됩니다. 사이트가 배포되면 프로덕션에 배포될 때 netlify.app 의 하위 도메인이 할당됩니다. Netlify Edge는 미리보기 및 분기 배포(스테이징, 개발 등)도 지원합니다.

Netlify Forms 제출 처리는 구축 봇이 배포 중에 사이트의 HTML 양식을 구문 분석하기 때문에 작동합니다. 컴파일된 Angular 사이트와 같은 클라이언트 측 Javascript 렌더링 양식은 이러한 봇에서 찾을 수 없습니다. 따라서 Netlify Forms에 대한 일반 설정은 Angular Forms에서 작동하지 않습니다.

그러나 이에 대한 해결 방법이 있습니다. 제출을 받기 위해 숨겨진 일반 HTML 양식이 index.html 파일에 추가됩니다. 이 양식은 빌드 봇과 함께 작동합니다. Angular 양식을 제출할 때 이 숨겨진 양식에 대한 게시 요청이 이루어지며 이 양식은 Netlify Forms에 의해 캡처됩니다.

이 기사에서는 반응형을 만들 것입니다. 또한 숨겨진 HTML 양식에 대해 게시 요청을 하는 서비스를 개발할 것입니다. 마지막으로 Netlify Edge에 앱을 배포합니다.

예시

앱을 구축하는 방법을 설명하기 위해 많은 웹사이트에서 흔히 볼 수 있는 피드백 양식의 예를 들어보겠습니다. 우리는 이 양식을 사용하여 이름 및 이메일과 함께 사이트 사용자의 의견/불만, 질문 및 제안을 수집합니다. 우리는 또한 사이트에 대한 그들의 평가를 수집하는 데 사용할 것입니다.

요구 사항

이 튜토리얼을 따라 하려면 Netlify 계정과 Angular CLI가 설치되어 있어야 합니다. CLI가 없는 경우 npm을 사용하여 설치할 수 있습니다.

 npm install -g @angular/cli

아직 Netlify 계정에 가입하지 않았다면 여기에서 만들 수 있습니다. Netlify는 Github, Gitlab, Bitbucket 또는 이메일을 통한 가입을 제공합니다. 선택하는 배포 방법에 따라 다른 요구 사항이 있을 수 있습니다. 각 배포 방법에 설명되어 있습니다.

점프 후 더! 아래에서 계속 읽기 ↓

앱 설정

시작하려면 앱을 만들고 이를 feedback 이라고 합니다. 생성할 때 프롬프트에서 요청하면 라우팅을 추가합니다.

 ng new feedback

다음으로 피드백 양식, 성공적인 제출 메시지 페이지 및 404 페이지의 세 가지 구성 요소를 생성합니다. Netlify Forms를 사용하면 성공적인 양식 입력 제출 시 페이지로 이동할 수 있습니다. 그것이 우리가 SuccessComponent 를 사용하는 이유입니다.

 ng gc feedback ng gc success ng gc page-not-found

구성 요소를 생성한 후 app-routing.module.ts 파일 내 AppRoutingModule 의 각 페이지에 대한 경로를 추가합니다.

 const routes: Routes = [ { path:'', component: FeedbackComponent }, { path: 'success', component: SuccessComponent }, { path: '**', component: PageNotFoundComponent } ];

FormBuilder 서비스를 사용하여 반응형 양식을 만듭니다. 기본 폼 컨트롤을 사용하는 것보다 더 편리하고 덜 반복적이기 때문입니다. 액세스하려면 app.module.ts 파일에 ReactiveFormsModule 을 등록해야 합니다.

숨겨진 HTML 양식에 대한 게시 요청을 만들 것이므로 HttpClientModule 도 등록해야 합니다.

 import { ReactiveFormsModule } from '@angular/forms'; import { HttpClientModule } from '@angular/common/http'; @NgModule({ imports: [ // other imports ReactiveFormsModule, HttpClientModule ] }) export class AppModule { }

라우터 콘센트만 갖도록 app.component.html 의 내용을 변경합니다.

 <router-outlet></router-outlet>

다른 페이지는 일부 스타일을 공유합니다. 따라서 아래 스타일을 styles.css 에 추가하십시오.

 html, body { height: 100%; width: 100%; display: flex; align-items: flex-start; justify-content: center; } h1 { margin: 0; text-align: center; } h1, p, label { font-family: Arial, Helvetica, sans-serif; } p { max-width: 25rem; } #container { border: none; padding: .4rem; border-radius: 0; flex-direction: column; display: flex; } hr { width: 80%; } button { color: white; background-color: black; font-size: large; padding: .5rem; border-radius: .5rem; margin-top: 1rem; } @media screen and (min-height: 700px) { html, body { align-items: center; justify-content: center; } } @media screen and (min-width: 480px) { #container { border: .1rem solid lightgray; padding: 2rem; border-radius: .5rem; } html, body { align-items: center; justify-content: center; } }

반응형 양식 만들기

FeedbackComponent 클래스에서 먼저 양식을 만드는 데 사용할 FormBuilder 서비스를 가져옵니다. 또한 양식 입력 유효성 검사를 위해 Validators 클래스를 가져올 것입니다.

 import { FormBuilder, Validators } from '@angular/forms';

그런 다음 FeedbackComponent 생성자에 FormBuilder 서비스를 추가하여 주입합니다.

 constructor(private fb: FormBuilder) { }

다음으로 주입된 FormBuilder 서비스의 group 메서드를 사용하여 폼 모델을 정의합니다. 또한 양식 입력을 제출할 때 발생할 수 있는 오류를 보유하기 위해 errorMsg 속성을 추가합니다. 또한 양식에 표시되는 오류 경고를 닫는 closeError 메서드도 포함되어 있습니다.

양식 모델의 각 컨트롤은 Validators 클래스의 유효성 검사기를 사용하여 확인됩니다. 입력 중 하나라도 유효성 검사에 실패하면 양식이 무효화되고 제출이 비활성화됩니다. email 컨트롤의 경우와 같이 양식 컨트롤에 여러 유효성 검사기를 추가하도록 선택할 수 있습니다.

 export class FeedbackComponent { feedbackForm = this.fb.group({ firstName: ['', Validators.required], lastName: ['', Validators.required], email: ['', [Validators.email, Validators.required]], type: ['', Validators.required], description: ['', Validators.required], rating: [0, Validators.min(1)] }); errorMsg = ''; closeError() { this.errorMsg = ''; } // ... }

컴포넌트의 템플릿( feedback.component.html )에서 이것을 추가할 것입니다.

 <div> <div class="error" [class.hidden]="errorMsg.length == 0"> <p>{{errorMsg}}</p> <span (click)="closeError()" class="close">︎</span> </div> <h1>Feedback Form</h1> <hr> <p>We'd like your feedback to improve our website.</p> <form [formGroup]="feedbackForm" name="feedbackForm" (ngSubmit)="onSubmit()"> <div> <p class="radioOption"> <input formControlName="type" type="radio" name="type" value="suggestion"> <label for="suggestion">Suggestion</label><br> </p> <p class="radioOption"> <input formControlName="type" type="radio" name="type" value="comment"> <label for="comment">Comment</label><br> </p> <p class="radioOption"> <input formControlName="type" type="radio" name="type" value="question"> <label for="question">Question</label><br> </p> </div> <div class="inputContainer"> <label>Description:</label> <textarea rows="6" formControlName="description"></textarea> </div> <div class="inputContainer"> <div> <label>How would you rate our site?</label> <label>{{feedbackForm.value?.rating}}</label> </div> <input formControlName="rating" type="range" name="rating" max="5"> </div> <div class="inputContainer"> <label>Name:</label> <div class="nameInput"> <input formControlName="firstName" type="text" name="firstName" placeholder="First"> <input formControlName="lastName" type="text" name="lastName" placeholder="Last"> </div> </div> <div class="inputContainer"> <label>Email:</label> <input formControlName="email" type="email" name="email"> </div> <div class="inputContainer"> <button type="submit" [disabled]="feedbackForm.invalid">Submit Feedback</button> </div> </form> </div>

form 요소에는 방금 생성한 모델에 해당하는 [formGroup]="feedbackForm" 속성이 있어야 합니다. 또한 각 입력 요소에는 모델의 해당 양식 컨트롤에 해당하는 formControlName="" 속성이 있어야 합니다.

양식의 스타일을 지정하려면 이를 feedback.component.css 에 추가하세요.

 #options { display: flex; flex-direction: column; } #options label { margin: 0 0 0 .2rem; } .radioOption { margin: 0 0 .2rem 0; } .inputContainer { display: flex; flex-direction: column; margin: .5rem 0 .5rem 0; } label { margin: .5rem 0 .5rem 0; } .nameInput { display: flex; flex-direction: column; } button:disabled { cursor: not-allowed; pointer-events: all; background-color: slategrey; } #ratingLabel { display: flex; justify-content: space-between; margin: .5rem 0 .5rem 0; } #ratingValue { font-weight: bolder; font-size: large; border: .1rem solid lightgray; padding: .4rem .6rem .1rem .6rem; margin: 0; vertical-align: middle; border-radius: .3rem; } .error { color: darkred; background-color: lightsalmon; border: .1rem solid crimson; border-radius: .3rem; padding: .5rem; text-align: center; margin: 0 0 1rem 0; display: flex; width: inherit; } .error p { margin: 0; flex-grow: 1; } textarea, input { margin: .1rem; font-family: Arial, Helvetica, sans-serif; padding: 5px; font-size: medium; font-weight: lighter; } .close { cursor: default; } .hidden { display: none; } @media screen and (min-width: 480px) { #options { flex-direction: row; justify-content: space-around; } .nameInput { flex-direction: row; justify-content: space-between; } }

형식은 다음과 같습니다.

피드백 폼
피드백 양식 스크린샷(큰 미리보기)

숨겨진 HTML 양식 추가하기

앞서 언급했듯이 Netlify Forms 빌드 봇이 구문 분석할 수 있는 숨겨진 HTML 양식을 추가해야 합니다. 그런 다음 제출물은 반응 양식에서 숨겨진 HTML 양식으로 전송됩니다. HTML 양식은 index.html 파일에 저장됩니다.

이 양식은 반응 양식과 이름이 같아야 합니다. 또한 netlify , netlify-honeypothidden 의 세 가지 다른 속성을 포함해야 합니다. 봇은 Netlify가 입력을 처리할 수 있도록 netlify 속성이 있는 모든 양식을 찾습니다. netlify-honeypot 속성은 제출 시 보안 문자가 표시되는 것을 방지하고 추가 스팸 보호를 활성화하기 위해 추가되었습니다.

 <!doctype html> <html lang="en"> <!-- Head --> <body> <form name="feedbackForm" netlify netlify-honeypot="bot-field" hidden> <input type="text" name="firstName"/> <input type="text" name="lastName"/> <input type="text" name="email"/> <input type="text" name="feedbackType"/> <input type="text" name="description"/> <input type="text" name="rating"/> </form> <app-root></app-root> </body> </html>

file 입력 요소의 값을 설정할 수 없으므로 이 방법으로 파일을 업로드할 수 없다는 점에 유의해야 합니다.

히든폼에 포스트 요청하기

반응 양식에서 HTML 양식으로 제출물을 보내기 위해 index.html 제출물이 포함된 게시 요청을 만듭니다. 작업은 FeedbackComponentonSubmit 메서드에서 수행됩니다.

그러나 그렇게 하기 전에 Feedback 인터페이스와 NetlifyFormsService 라는 두 가지를 만들어야 합니다. 인터페이스부터 시작하겠습니다.

 touch src/app/feedback/feedback.ts

이 파일의 내용은 다음과 같습니다.

 export interface Feedback { firstName: string; lastName: string; email: string; type: string; description: string; rating: number; }

NetlifyFormsService 에는 피드백 항목을 제출하는 공개 메서드, 일반 항목을 제출하는 비공개 메서드, 오류를 처리하는 다른 비공개 메서드가 포함됩니다. 추가 양식에 대해 다른 공개 메소드를 추가할 수 있습니다.

생성하려면 다음을 실행하십시오.

 ng gs netlify-forms/netlify-forms

submitEntry 메소드는 Observable<string> 을 반환합니다. Netlify가 양식에 데이터를 게시하면 성공 경고가 포함된 HTML 페이지를 보내기 때문입니다. 이것은 서비스입니다:

 import { Injectable } from '@angular/core'; import { HttpClient, HttpErrorResponse, HttpParams } from '@angular/common/http'; import { Feedback } from '../feedback/feedback'; import { Observable, throwError } from 'rxjs'; import { catchError } from 'rxjs/operators'; @Injectable({ providedIn: 'root' }) export class NetlifyFormsService { constructor(private http: HttpClient) { } submitFeedback(fbEntry: Feedback): Observable { const entry = new HttpParams({ fromObject: { 'form-name': 'feedbackForm', ...fbEntry, 'rating': fbEntry.rating.toString(), }}); return this.submitEntry(entry); } private submitEntry(entry: HttpParams): Observable { return this.http.post( '/', entry.toString(), { headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, responseType: 'text' } ).pipe(catchError(this.handleError)); } private handleError(err: HttpErrorResponse) { let errMsg = ''; if (err.error instanceof ErrorEvent) { errMsg = `A client-side error occurred: ${err.error.message}`; } else { errMsg = `A server-side error occurred. Code: ${err.status}. Message: ${err.message}`; } return throwError(errMsg); } } import { Injectable } from '@angular/core'; import { HttpClient, HttpErrorResponse, HttpParams } from '@angular/common/http'; import { Feedback } from '../feedback/feedback'; import { Observable, throwError } from 'rxjs'; import { catchError } from 'rxjs/operators'; @Injectable({ providedIn: 'root' }) export class NetlifyFormsService { constructor(private http: HttpClient) { } submitFeedback(fbEntry: Feedback): Observable { const entry = new HttpParams({ fromObject: { 'form-name': 'feedbackForm', ...fbEntry, 'rating': fbEntry.rating.toString(), }}); return this.submitEntry(entry); } private submitEntry(entry: HttpParams): Observable { return this.http.post( '/', entry.toString(), { headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, responseType: 'text' } ).pipe(catchError(this.handleError)); } private handleError(err: HttpErrorResponse) { let errMsg = ''; if (err.error instanceof ErrorEvent) { errMsg = `A client-side error occurred: ${err.error.message}`; } else { errMsg = `A server-side error occurred. Code: ${err.status}. Message: ${err.message}`; } return throwError(errMsg); } } import { Injectable } from '@angular/core'; import { HttpClient, HttpErrorResponse, HttpParams } from '@angular/common/http'; import { Feedback } from '../feedback/feedback'; import { Observable, throwError } from 'rxjs'; import { catchError } from 'rxjs/operators'; @Injectable({ providedIn: 'root' }) export class NetlifyFormsService { constructor(private http: HttpClient) { } submitFeedback(fbEntry: Feedback): Observable { const entry = new HttpParams({ fromObject: { 'form-name': 'feedbackForm', ...fbEntry, 'rating': fbEntry.rating.toString(), }}); return this.submitEntry(entry); } private submitEntry(entry: HttpParams): Observable { return this.http.post( '/', entry.toString(), { headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, responseType: 'text' } ).pipe(catchError(this.handleError)); } private handleError(err: HttpErrorResponse) { let errMsg = ''; if (err.error instanceof ErrorEvent) { errMsg = `A client-side error occurred: ${err.error.message}`; } else { errMsg = `A server-side error occurred. Code: ${err.status}. Message: ${err.message}`; } return throwError(errMsg); } }

양식 제출을 HttpParams 로 보냅니다. ContentType 의 헤더는 application/x-www-form-urlencoded 값과 함께 포함되어야 합니다. responseType 옵션은 text 로 지정됩니다. 성공할 경우 숨겨진 양식에 게시하면 Netlify의 일반 성공 메시지가 포함된 HTML 페이지가 반환되기 때문입니다. 이 옵션을 포함하지 않으면 응답이 JSON 으로 구문 분석되므로 오류가 발생합니다. 아래는 일반적인 Netlify 성공 메시지의 스크린샷입니다.

양식/Netlify 일반 성공 메시지
Netlify 일반 성공 메시지 스크린샷(큰 미리보기)

FeedbackComponent 클래스에서 NetlifyFormsServiceRouter 를 가져올 것입니다. NetlifyFormsService.submitEntry 메서드를 사용하여 양식 항목을 제출합니다. 제출이 성공하면 성공적인 제출 페이지로 리디렉션되고 양식을 재설정합니다. 리디렉션을 위해 Router 서비스를 사용합니다. 실패하면 errorMsg 속성에 오류 메시지가 할당되고 양식에 표시됩니다.

 import { Router } from '@angular/router'; import { NetlifyFormsService } from '../netlify-forms/netlify-forms.service';

그런 다음 생성자에 NetlifyFormsServiceRouter 를 모두 삽입합니다.

 constructor( private fb: FormBuilder, private router: Router, private netlifyForms: NetlifyFormsService ) {}

마지막으로 FeedbackComponent.onSubmit 에서 NetlifyFormsService.submitEntry 메서드를 호출합니다.

 onSubmit() { this.netlifyForms.submitFeedbackEntry(this.feedbackForm.value).subscribe( () => { this.feedbackForm.reset(); this.router.navigateByUrl('/success'); }, err => { this.errorMsg = err; } ); }

성공적인 제출 페이지 만들기

사용자가 제출을 완료하면 Netlify는 이전 섹션의 마지막 스크린샷에 표시된 일반 성공 메시지를 반환합니다. 그러나 사용자 정의 성공 메시지 페이지로 다시 연결할 수 있습니다. 숨겨진 HTML 양식에 action 속성을 추가하면 됩니다. 해당 값은 사용자 지정 성공 페이지에 대한 상대 경로입니다. 이 경로는 / 로 시작해야 하며 루트 사이트에 상대적이어야 합니다.

그러나 숨겨진 HTML 양식을 사용할 때 사용자 정의 성공 페이지 설정이 작동하지 않는 것 같습니다. 숨겨진 HTML 양식에 대한 게시 요청이 성공하면 일반 Netlify 성공 메시지를 HTML 페이지로 반환합니다. action 속성이 지정되어도 리디렉션되지 않습니다. 따라서 대신 Router 서비스를 사용하여 제출 후 성공 메시지 페이지로 이동합니다.

먼저 앞서 생성한 SuccessComponent 에 콘텐츠를 추가해 보겠습니다. success.component.html 에서 다음을 추가하십시오.

 <div> <h1>Thank you!</h1> <hr> <p>Your feedback submission was successful.</p> <p>Thank you for sharing your thoughts with us!</p> <button routerLink="/">Give More Feedback</button> </div>

페이지의 스타일을 지정하려면 다음을 success.component.css 에 추가하십시오.

 p { margin: .2rem 0 0 0; text-align: center; }

페이지는 다음과 같습니다.

성공적인 제출 페이지
성공적인 제출 페이지의 스크린샷(큰 미리보기)

FeedbackComponent 클래스에서 이미 Router 서비스를 가져오기로 추가하고 생성자에 주입했습니다. onSubmit 메소드에서 요청이 성공하고 양식이 재설정된 후 성공적인 제출 페이지인 /success 로 이동합니다. 이를 위해 라우터의 navigateByUrl 메서드를 사용합니다.

404 페이지 만들기

404 페이지는 필요하지 않을 수 있지만 있으면 좋습니다. page-not-found.component.html 의 내용은 다음과 같습니다.

 <div> <h1>Page Not Found!</h1> <hr> <p>Sorry! The page does not exist.</p> <button routerLink="/">Go to Home</button> </div>

스타일을 지정하려면 page-not-found.component.css 에 다음을 추가하세요.

 p { text-align: center; }

이것이 404 페이지의 모습입니다.

404 페이지
404 페이지의 스크린샷(큰 미리보기)

배포 전 라우팅 수정

Router 서비스를 사용하기 때문에 모든 라우팅은 클라이언트에서 수행됩니다. 앱의 페이지에 대한 링크가 주소 표시줄(딥 링크)에 붙여넣거나 페이지 새로 고침이 있는 경우 해당 요청이 서버로 전송됩니다. 우리 앱의 프론트엔드에서 구성되었기 때문에 서버에는 경로가 포함되어 있지 않습니다. 이러한 경우에는 404 상태를 받게 됩니다.

이 문제를 해결하려면 Netlify 서버에 모든 요청을 index.html 페이지로 리디렉션하도록 지시해야 합니다. 이런 식으로 Angular 라우터가 처리할 수 있습니다. 관심이 있는 경우 여기 및 여기에서 이 현상에 대해 자세히 읽을 수 있습니다.

src 폴더에 _redirects 파일을 만드는 것으로 시작하겠습니다. _redirects 파일은 Netlify 사이트에 대한 리디렉션 및 다시 쓰기 규칙을 지정하는 일반 텍스트 파일입니다. 사이트 게시 사이트 디렉토리( dist/<app_name> )에 있어야 합니다. src 폴더에 저장하고 angular.json 파일의 자산으로 지정합니다. 앱이 컴파일되면 dist/<app_name> 에 배치됩니다.

 touch src/_redirects

이 파일에는 아래 규칙이 포함됩니다. 이는 서버에 대한 모든 요청이 index.html 로 리디렉션되어야 함을 나타냅니다. 또한 이러한 리디렉션이 200 상태를 반환해야 함을 나타내기 위해 끝에 HTTP 상태 코드 옵션을 추가합니다. 기본적으로 301 상태가 반환됩니다.

 /* /index.html 200

마지막으로 해야 할 일은 er projects > {your_project_name} > architect > options > assets 아래의 angular.json 에 아래 옵션을 추가하는 것입니다. assets 배열에 포함:

 { "glob": "_redirects", "input": "src", "output": "/" }

로컬에서 앱 미리보기

피드백 앱을 배포하기 전에 미리 보는 것이 가장 좋습니다. 이를 통해 사이트가 의도한 대로 작동하는지 확인할 수 있습니다. 무엇보다도 리소스에 대한 경로가 끊어지는 것과 같은 빌드 프로세스로 인해 발생하는 문제를 발견할 수 있습니다. 먼저 앱을 빌드해야 합니다. 그런 다음 서버를 사용하여 컴파일된 버전을 제공합니다. 웹 앱용 경량 라이브 다시 로드 서버인 lite-server를 사용할 것입니다.

참고 : 앱이 아직 Netlify에 배포되지 않았기 때문에 게시 요청을 시도하면 404 오류가 발생합니다. Netlify Forms는 배포된 앱에서만 작동하기 때문입니다. 아래 스크린샷과 같이 양식에 오류가 표시되지만 배포한 후에는 작동합니다.

피드백 양식 오류
피드백 양식의 오류 스크린샷(큰 미리보기)
  1. 시작하려면 lite-server를 설치하십시오:
     npm install lite-server --save-dev
  2. 다음으로 앱의 작업 공간 디렉터리 내에서 앱을 빌드합니다. 파일이 변경될 때마다 빌드가 실행되도록 하려면 --watch 플래그를 전달하세요. 앱이 컴파일되면 결과가 dist/<app name> 출력 디렉터리에 기록됩니다. 버전 관리 시스템을 사용하는 경우 dist 폴더가 생성되고 미리 보기용이므로 체크인하지 않도록 하십시오.
     ng build --watch
  3. 컴파일된 사이트를 제공하려면 빌드 출력 디렉토리에 대해 lite-server 를 실행하십시오.
     lite-server --baseDir="dist/<app name>"

사이트는 이제 localhost:3000 에서 제공됩니다. 배포를 시작하기 전에 브라우저에서 확인하고 예상대로 작동하는지 확인하십시오.

전개

Angular 프로젝트를 Netlify Edge에 배포하는 방법에는 여러 가지가 있습니다. 우리는 여기에서 세 가지를 다룰 것입니다:

  1. netlify-builder 사용,
  2. Git과 Netlify 웹 UI를 사용하여
  3. Netlify CLI 도구 사용.

1. netlify-builder 사용

netlify-builder는 Angular CLI를 통해 Angular 앱 배포를 용이하게 합니다. 이 방법을 사용하려면 Angular CLI v8.3.0 이상을 사용하여 앱을 생성해야 합니다.

  1. Netlify 대시보드의 사이트 탭에서 새 프로젝트를 만듭니다. Git을 사용하여 프로젝트를 생성하지 않을 것이므로 "여기에 사이트 폴더를 끌어다 놓기" 라고 표시된 점선 테두리 영역으로 빈 폴더를 끌어다 놓습니다. 그러면 임의의 이름으로 프로젝트가 자동으로 생성됩니다. 원하는 경우 나중에 사이트의 도메인 설정에서 이 이름을 변경할 수 있습니다.
    프로젝트를 생성하기 위한 대시보드 스크린샷
    프로젝트를 생성하기 위한 대시보드 스크린샷(큰 미리보기)

    프로젝트가 생성되면 이것이 표시되어야 합니다.
    샘플 프로젝트의 프로젝트 페이지 스크린샷
    샘플 프로젝트의 프로젝트 페이지 스크린샷(큰 미리보기)
  2. 이 방법을 사용하여 배포하기 전에 계정에서 Netlify 프로젝트의 API ID 와 Netlify 개인 액세스 토큰 을 가져와야 합니다. 사이트 설정에서 프로젝트 API ID를 얻을 수 있습니다. 사이트 설정 > 일반 > 사이트 세부 정보 > 사이트 정보 에서 프로젝트의 API ID를 찾을 수 있습니다.
    사이트 설정 버튼의 위치를 ​​보여주는 스크린샷
    사이트 설정 버튼의 위치를 ​​보여주는 스크린샷(큰 미리보기)
    설정에서 사이트의 API ID가 있는 위치를 보여주는 스크린샷
    설정에서 사이트의 API ID가 있는 위치를 보여주는 스크린샷(큰 미리보기)

    사용자 설정에서 개인 액세스 토큰을 얻을 수 있습니다. 사용자 설정 > 애플리케이션 > 개인 액세스 토큰 에서 새 액세스 토큰 버튼을 클릭합니다. 메시지가 표시되면 토큰에 대한 설명을 입력한 다음 토큰 생성 버튼을 클릭합니다. 토큰을 복사합니다. 지속성을 위해 이 값을 프로젝트 내의 .env 파일에 저장할 수 있지만 버전 제어 시스템을 사용하는 경우 이 파일을 체크인하지 마십시오.
    사용자 설정 버튼의 위치를 ​​보여주는 스크린샷
    사용자 설정 버튼의 위치를 ​​보여주는 스크린샷(큰 미리보기)
    개인 액세스 토큰을 생성하는 위치를 보여주는 스크린샷
    개인 액세스 토큰을 생성할 위치를 보여주는 스크린샷(큰 미리보기)
    토큰 설명을 입력할 위치를 보여주는 스크린샷
    토큰 설명을 입력할 위치를 보여주는 스크린샷(큰 미리보기)
    토큰 값을 보여주는 스크린샷
    토큰 값을 보여주는 스크린샷(큰 미리보기)
  3. 다음으로 ng add 를 사용하여 프로젝트에 netlify-builder 를 추가합니다.
     ng add @netlify-builder/deploy
    설치가 완료되면 API ID와 개인 액세스 토큰을 추가하라는 메시지가 표시됩니다.
    netlify 빌더를 추가할 때의 프롬프트를 보여주는 스크린샷
    netlify 빌더를 추가할 때의 프롬프트를 보여주는 스크린샷(큰 미리보기)

    여기에 추가하는 것은 선택 사항입니다. 버전 제어 시스템을 사용하는 경우 일반적으로 체크인되는 angular.json 파일에 추가되므로 이 프롬프트를 무시할 수 있습니다. 이런 종류의 민감한 정보를 코드 저장소에 저장하는 것은 안전하지 않습니다. 이 파일을 체크인하지 않는 경우 API ID와 개인 액세스 토큰을 입력하면 됩니다. 아래 항목은 architect 설정 아래의 angular.json 파일에서 수정됩니다.
     "deploy": { "builder": "@netlify-builder/deploy:deploy", "options": { "outputPath": "dist/<app name>", "netlifyToken": "", "siteId": "" } }
  4. 남은 것은 다음을 실행하여 애플리케이션을 배포하는 것입니다.
     NETLIFY_TOKEN=<access token> NETLIFY_API_ID=<api id> ng deploy
    또는 이를 스크립트에 넣고 앱을 배포해야 할 때 실행할 수 있습니다.
     # To create the script touch deploy.sh && echo "NETLIFY_TOKEN=<access token> NETLIFY_API_ID=<api id> ng deploy" >> deploy.sh && chmod +x deploy.sh # To deploy ./deploy.sh
    다음은 이 명령을 실행한 후 표시되어야 하는 출력입니다.
    배포 결과를 보여주는 스크린샷
    배포 결과를 보여주는 스크린샷(큰 미리보기)

2. Git과 Netlify 웹 UI 사용하기

Angular 앱의 코드가 Github, Bitbucket 또는 Gitlab에서 호스팅되는 경우 Netlify의 웹 UI를 사용하여 프로젝트를 호스팅할 수 있습니다.

  1. Netlify 대시보드의 사이트 탭에서 " Git에서 새 사이트” 버튼.
    새 사이트를 만드는 버튼을 보여주는 스크린샷
    새 사이트를 만드는 버튼을 보여주는 스크린샷(큰 미리보기)
  2. 코드 리포지토리 서비스에 연결합니다. 앱 코드가 호스팅되는 서비스를 선택하세요. Netlify가 리포지토리를 볼 수 있도록 승인하라는 메시지가 표시됩니다. 이것은 서비스마다 다릅니다.
    Git 공급자에 연결하기 위한 옵션을 보여주는 스크린샷
    Git 공급자에 연결하기 위한 옵션을 보여주는 스크린샷(큰 미리보기)
  3. 코드 저장소를 선택하십시오.
    사용 가능한 저장소 목록을 보여주는 스크린샷
    사용 가능한 리포지토리 목록을 보여주는 스크린샷(큰 미리보기)
  4. 다음으로 배포 및 빌드 설정을 지정합니다. 이 경우 배포할 분기를 선택하고 빌드 명령을 ng deploy --prod 로, 게시 디렉터리를 dist/<your app name> 으로 지정합니다.
    빌드 및 배포 설정을 보여주는 스크린샷
    빌드 및 배포 설정을 보여주는 스크린샷(큰 미리보기)
  5. 사이트 배포 버튼을 클릭하면 완료됩니다.

3. Netlify CLI 도구 사용

  1. 시작하려면 다음과 같이 Netlify CLI 도구를 설치하십시오.
     npm install netlify-cli -g
    설치에 성공하면 터미널에 다음 결과가 표시되어야 합니다.
    Netlify CLI 설치 성공 결과를 보여주는 스크린샷
    Netlify CLI 설치 성공 결과를 보여주는 스크린샷(큰 미리보기)
  2. 다음을 실행하여 Netlify에 로그인합니다.
     netlify login
    이 명령을 실행하면 Netlify CLI를 인증하라는 메시지가 표시되는 브라우저 창으로 이동합니다. Authorize 버튼을 클릭합니다. 그런 다음 승인이 부여되면 탭을 닫을 수 있습니다.
    Netlify CLI 승인을 요청하는 대화 상자를 보여주는 스크린샷
    Netlify CLI 승인을 요청하는 대화 상자를 보여주는 스크린샷(큰 미리보기)
    권한 부여 대화 상자를 보여주는 스크린샷
    권한 부여 대화 상자를 보여주는 스크린샷(큰 미리보기)
  3. 새 Netlify 프로젝트를 생성하려면 터미널에서 다음을 실행하십시오.
     netlify init
    Angular 앱을 기존 Netlify 프로젝트에 연결하거나 새 프로젝트를 생성하라는 메시지가 표시됩니다. 새 사이트 만들기 및 구성 옵션을 선택합니다.
    프로젝트 생성 또는 연결 옵션을 보여주는 스크린샷
    프로젝트 생성 또는 연결 옵션을 보여주는 스크린샷(큰 미리보기)
    다음으로 팀과 배포할 사이트의 이름을 선택합니다. 프로젝트가 생성되면 CLI 도구가 프로젝트에 대한 사이트 세부 정보를 나열합니다.
    새 사이트에 대한 세부정보를 보여주는 스크린샷
    새 사이트에 대한 세부 정보를 보여주는 스크린샷(큰 미리보기)
    그런 다음 CLI 도구는 Netlify 계정을 Git 호스팅 공급자에 연결하여 웹훅을 구성하고 키를 배포하라는 메시지를 표시합니다. 이를 거부할 수 없습니다. 로그인 옵션을 선택한 다음 Netlify를 인증하세요.
    Git 공급자에 연결하라는 메시지를 보여주는 스크린샷
    Git 공급자에 연결하라는 메시지를 보여주는 스크린샷(큰 미리보기)
    다음으로 빌드 명령을 입력하라는 메시지가 표시됩니다. 사용:
     ng build --prod
    그런 다음 배포할 디렉터리를 제공하라는 메시지가 표시됩니다. 앱 이름과 함께 dist/<app name> 을 입력합니다.
    빌드 설정 프롬프트를 보여주는 스크린샷
    빌드 설정 프롬프트를 보여주는 스크린샷(큰 미리보기)
    이 작업이 끝나면 명령이 완료되고 이 출력이 표시됩니다.
    성공적인 프로젝트 초기화 결과를 보여주는 스크린샷
    성공적인 프로젝트 초기화 결과를 보여주는 스크린샷(큰 미리보기)
  4. 앱을 배포하려면 다음을 실행하세요.
     netlify deploy --prod
    --prod 플래그를 사용하면 빌드가 프로덕션에 배포됩니다. 이 플래그를 생략하면 netlify deploy 명령이 테스트 및 미리보기에 사용되는 고유한 초안 URL에 빌드를 배포합니다. 배포가 완료되면 다음 출력이 표시되어야 합니다.
    성공적인 배포 결과를 보여주는 스크린샷
    성공적인 배포 결과를 보여주는 스크린샷(큰 미리보기)

제출 양식 보기

제출된 양식은 사이트의 양식 탭 아래에 있는 Netlify 대시보드에서 볼 수 있습니다. app.netlify.com/sites/<your_site_name>/forms 에서 찾을 수 있습니다. 이 페이지에는 모든 활성 양식이 나열됩니다. 숨겨진 양식 요소에 적는 name 속성은 대시보드에 있는 양식의 이름입니다.

양식을 선택하면 해당 양식에 대한 모든 제출물이 나열됩니다. 모든 항목을 CSV 파일로 다운로드하거나 스팸으로 표시하거나 삭제할 수 있습니다.

활성 양식 목록
사이트 대시보드에 나열된 활성 양식의 스크린샷(큰 미리보기)
양식 항목
양식 대시보드에 나열된 양식 항목의 스크린샷(큰 미리보기)

결론

Netlify Forms를 사용하면 백엔드를 생성하거나 구성하지 않고도 앱에서 양식 제출을 수집할 수 있습니다. 이는 연락처 정보, 고객 피드백, 이벤트 등록 등과 같은 제한된 양의 데이터만 수집해야 하는 앱에서 특히 유용할 수 있습니다.

Angular 반응형 양식을 Netlify 양식과 페어링하면 데이터 모델을 구성할 수 있습니다. Angular 반응형은 데이터 모델과 양식 요소가 서로 동기화된다는 추가 이점이 있습니다. UI 렌더링에 의존하지 않습니다.

Netlify Forms는 Netlify Edge에 배포된 경우에만 작동하지만 호스팅 플랫폼은 매우 강력하고 A/B 테스트와 같은 유용한 기능을 제공하며 앱 빌드 및 배포를 자동화합니다.

  • 이 프로젝트의 소스 코드 보기 →

여기에서 양식과 함께 Netlify를 사용하는 방법에 대한 자세한 내용을 계속 읽을 수 있습니다.