210821 "Zone.js has detected that ZoneAwarePromise (window|global).Promise has been overwritten

디버깅 결과 페이지

이번 포스팅에서는 현재 서비스 중인 Angular web app이 iOS 모바일 단말기에서 정상적으로 동작하지 않는 문제에 대해서 작성해보려고 한다.

[Issue]

브라우저에서 디버깅해본 결과, 위의 ERROR를 확인할 수 있었다.
현재 Promise polyfill과 zone.js가 로드되는 과정에서 문제가 되고 있다. 프로젝트 내에서는 zone.js가 로드된 다음에 Promise polyfill가 로드되고 있지만, 이 문제를 해결하기 위해서는 Promise polyfill이 로드된 다음에 zone.js가 로드되어야 한다.
그 이유는 Zone.js의 ZoneAwarePromise가 다음에 로드된 Promise polyfill에 의해 Overwritten되기 때문이다.

[Solution]

현재 프론트엔드 프로젝트의 src/polyfills.ts의 코드를 보면, import 'zone.js/dist/zone'; statement를 확인 할 수 있다. Promise polyfill 다음으로 zone.js를 로드하기 위해서는 앞서 언급한 statement를 main.js로 이전해서 작성해줘야 한다.

(위의 Solution을 적용한 뒤에 정상적으로 동작을 하는지 확인이 필요)

[Promise polyfills과 zone.js의 역할]

Promise polyfills

비동기 코드의 장점을 살리면서 콜백지옥(callback hell)을 피하기 위해 ES6 표준 spec에 포함되어있는 Promise 패턴을 사용한다. 이 Promise polyfill을 사용해서 Promise가 지원되지 않는 브라우저에서 사용될 수 있도록 해야한다.

https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Promise

zone.js(Zones)

Zones는 Angular의 Change Detection을 위해 중요한 역할을 한다. Angular에서는 click, change, input, submit과 같은 사용자에 의한 이벤트XMLHttpRequest를 통한 원격 서버로부터의 데이터 취득, setTimeout과 setInterval을 통해 앱의 상태를 변화시키고 있다.
Angular에서는 화면을 업데이트하는데 위와 같은 비동기 처리를 사용하고, 로직이 작성되어있는 ts 파일의 변수가 HTML Template에 바인딩되어 ts파일내의 변수의 값이 업데이트되었을때 Template내의 값도 같이 업데이트된다.

이처럼 별도로 프레임워크에 변화가 일어났다는 작업을 하지 않아도 Angular는 알아서 처리를 해주게 되는데, 이때 중요한 역할을 해주는 것이 바로 Zones이다.
Angular의 Zones의 onTurnDone 이벤트가 발생할때마다 전체 어플리케이션에 대해 Change Detection을 수행하게 되고, onTurnDone 이벤트는 Angular의 NgZone이 발생을 시킨다.

ref. Zones를 이용하면, 해당 Zones(JavaScript Execution context)가 실행되는 시점에서 여러 이벤트들을 hooking할 수 있다.

(자바스크립트의 실행 영역을 직접 나누는 것을 도와주기 때문에 여러가지 이벤트들을 hooking하는 것이 가능)

이러한 변화감지는 Zones 덕분에 가능한 것이다.

이처럼 Zones는 Angular가 DOM을 언제 업데이트해야 하는지 쉽게 발견할 수 있게 도와주는 역할을 한다.

210620 RxJS (작성중...)

RxJS
본 블로그 포스팅은 RxJS와 관련하여 네이버의 손창욱님이 올려주신 유튜브 영상을 보고 정리해보았다.

RxJS를 처음 접하는 나와 같은 사람도 정말 쉽게 이해할 수 있도록 설명을 해주셔서 너무 유익했다.

모든 어플리케이션은 궁극적으로 상태머신들의 집합

Input(입력값)이 들어오면 logic을 통해 state가 업데이트되고, 업데이트된 state는 logic을 통해 Output(결과값)이 나온다.

RxJS

RxJS는 비동기 처리를 원할하게 할 수 있도록 도와주는 데이터 스트림으로 정의할 수 있다.

RxJS를 학습하기 위해서는 여러 새로운 용어들이 등장한다.(개별적으로 정리해서 공부)

동기/비동기 방식의 사용

동기 방식은 흐름이 그대로 가기 때문에 흐름을 쉽게 파악할 수 있지만, 비동기 처리는 굉장히 느린 처리나 사용자로부터 빠르게 interaction을 받아와야 하는 경우 그리고 높은 퍼포먼스가 요구되는 상황에서 사용이 된다.

RxJS의 역할

RxJS이외에도 Callback, Promise, Generator, Async/Await과 같은 표준을 사용하여 비동기 처리를 할 수 있는데 왜 굳이 RxJS를 사용해야 될까?

Callback함수를 사용해서 비동기 처리를 하는 경우, 에러에 대한 처리가 어렵고, 콜백 헬등의 분제가 발생한다.
Promise를 사용하는 것이 좀 더 나은 방법이긴 하지만, 한 번에 하나의 데이터를 처리하기 때문에 연속성을 갖는 데이터를 처리할 수 없다는 점과 서버로 보낸 요청을 취소할 수 없다는 단점이 있기 때문에 Observable을 사용하여 위의 단점을 보안해서 비동기 처리를 할 수 있다.

그리고 RxJS는비동기 처리 영역, 데이터 전파, 데이터 처리를 담당하며, 일관된 방식으로 안전하게 데이터 흐름을 처리하는 라이브러리이다.
여기서 일관된 방식이란 입력된 값의 타입에 따라 각 각 따로 처리를 하지 않고 하나의 방식으로 처리를 할 수 있다는 말이다.

  • [참고] 입력값에 따른 데이터 처리

    개발자가 처리하는 입력값에는 어떤 것들이 있을까?
    (1) 배열 데이터, 함수 반환값 : 동기 데이터를 처리하는 방식
    (2) 키보드/마우스 입력, 원격지 데이터, DB 데이터 : 비동기 데이터를 처리하는 방식

    위와 같이 RxJS이외의 Callback, Promise, Generator, Async/Await과 같은 표준을 사용하여 비동기 처리를 하게 되면, 데이터 처리 방식이 제각각이기 때문에 각기 다른 방식으로 처리를 해줘야 한다.

    하지만 RxJS는 동기/비동기와 관계없이 데이터를 시간축을 기준으로 연속적인 데이터 스트림으로 처리한다.

Read more

210617 Angular (작성중...)

Angular

이미 MERN(MongoDB,Express, React (+ Redux), NodeJS)의 구성으로 프로젝트를 진행해본 경험이 있기 때문에 Angular의 사용에 익숙해지면 좀 수월해질 것 같다.

그럼 Angular에 중점을 두고 MEAN의 구성으로 프로젝트를 만들어가면서 Angular의 사용에 익숙해지도록 해보자.

MEAN

M - MongoDB
E - ExpressJS
A - Angular
N - NodeJS

Angular에서 반복적으로 자주 사용되는 부분에 대해 복습을 하자.

컴포넌트의 selector는 snake case로 작성

template에서 커스텀 컴포넌트를 사용하는 경우, 각 컴포넌트에 정의되어있는 selector를 사용한다.
이 selector는 snake case로 작성하도록 한다.

@NgModule - declarations

상위 컴포넌트의 template 내에서 외부에서 작성한 커스텀 컴포넌트를 사용하기 위해서는 상위 컴포넌트가 정의되어있는 module decorator의 declarations에 정의해줘야 한다.
component가 아닌 moudle을 포함시키는 경우에는 imports에 module을 추가해준다.
exports는 외부에서 특정 컴포넌트를 사용하도록 해줄때 컴포넌트를 정의하는 부분이다. (확인필요)

@input() 데코레이터

상위 컴포넌트 템플릿에서 하위 커스텀 컴포넌트의 속성으로 상위 컴포넌트의 속성값을 넣어주는 경우,(React에서 부모 컴포넌트가 자식 컴포넌트에 props를 넘겨주는 것과 같은 경우) 하위 컴포넌트의 로직이 정의된 컴포넌트 클래스 내에 해당 속성의 변수를 정의하고 앞에 @input() 데코레이터를 사용해서 정의해준다.

@output() 데코레이터

자식 컴포넌트에서의 이벤트를 통해 부모 컴포넌트의 클래스에 정의된 속성값을 업데이트하는 경우,(React에서 자식 컴포넌트가 부모 컴포넌트로부터 이벤트 props를 전달받아 이벤트를 통해 부모 컴포넌트의 상태 데이터를 업데이트 하는 것과 같은 경우) React와 같이 부모 컴포넌트에서 속성에 대한 업데이트를 위한 함수를 자식 컴포넌트에 emitter를 통해 전달을 하고 있다. 자식 컴포넌트 클래스에서는 EventEmitter 인스턴스 변수를 @Output 데코레이터와 함께 선언하고 EventEmitter 인스턴스가 사용되는 함수를 정의한다.

Read more

210611 Angular - Angular 프로젝트의 실행흐름 이해하기, Module, Component, Template, 단방향 바인딩과 양방향 바인딩(React와 Angular 비교), Component의 스타일링, Pipe 사용

2021/06/12 단방향 바인딩과 양방향 바인딩 ~ Update

Angular

Angular 프로젝트의 전체적인 실행흐름 이해하기

Angular는 정해진 틀 안에서 구조화되어있기 때문에 사용하기 위해서는 어떤 흐름으로 컴포넌트가 정의가 되고 실행되는지 이해가 필요하다.
ReactJS는 라이브러리로 개발자가 폴더를 만들어서 직접 구조화시켜줘야 되지만, Angular는 플랫폼으로 이미 구조화된 틀이 있다는 차이가 있다. 하지만 React와 Angular 모두 컴포넌트 기반의 개발을 한다는 점에서 같다.

  • src/index.html
    React와 같이 Angular의 src 폴더에 정의된 index.html 파일을 보면, 별다른 script와 style을 로드하는 부분이 없고 webpack을 통해 번들링해서 index.html에 정의된 부분에 주입해서 보여준다.

  • src/main.ts
    프로젝트를 실행하게 되면 가장 먼저 호출되는 script 파일이 main.ts 이다.
    이 파일에서 중요한 부분은 AppModule(root module)을 실행하는 부분인데, platformBrowserDynamic 메서드와 bootstrapModule 메서드가 호출되고 있음을 알 수 있다.

    paltformBrowserDynamic : Angular가 작성한 코드를 컴파일해서 실행할 수 있는 JS 코드로 만들어주는 메서드이다. (브라우저에서 동적으로 컴파일한다)
    Angular는 서버나 브라우저 등 다양한 환경에서 실행될 수 있도록 rendering과 compile 프로세스가 분리되어있다.

    –aot(ahead of time compilation) 옵션을 사용해서 실행을 하면, 메서드를 다르게 해서 실행할 수 있다.

  • src/app/app.module.ts

    app.module.ts 파일은 앞서 살펴 본 main.ts에서 실행된 root module인 AppModule을 정의한 파일이다.
    class에 @NgModule 데코레이터로만 정의가 되어있는데, 이는 Angular module로 정의하는 데코레이터이다.

    데코레이터 내에 정의된 속성 중에 bootstrap을 살펴보면 root component인 AppComponent가 정의되어있음을 알 수 있다.

  • src/app/app.component.ts
    app.module.ts에서 bootstrap에 정의된 컴포넌트는 index.html에 주입해주는 컴포넌트이다.
    컴포넌트 데코레이터를 보면 selector 속성에 app-root값으로 설정이 되어있다. 이는 index.html에 정의된 <app-root>에 주입되는 컴포넌트라는 것을 의미한다.

Read more

210611 Angular - Angular 등장배경과 Angular 프로젝트 생성

Angular

Angular가 등장하게 된 배경

Angular가 등장하게 된 배경을 이해하기 위해서는 우선 웹 개발의 변화에 대한 이해가 필요하다.
변화는 Ajax - SPA(MVC) - Web Component 순으로 변화가 되었다.

Ajax를 사용하지 않는 웹 페이지의 경우, 브라우저에서 URL을 서버에 요청하게 되면 서버가 data(서버의 사용자 세션에 저장)를 사용해서 HTML 웹 페이지를 만들어서 응답으로 보내준다.

Ajax의 등장이후에는 한 번의 페이지를 받아온 이후에 ajax를 통해서 DOM element를 조작해서 페이지를 업데이트한다.

버튼 클릭과 같은 사용자 입력이 있는 경우, 데이터가 필요한 경우 ajax를 통해 서버로 요청을 보내고 서버로부터 json, xml 형태의 응답을 이용해서 DOM element를 업데이트하게 된다.

ajax를 이용하면, 화면이 바뀔때마다 서버로 요청을 보내는 것이 아니라, JavaScript를 사용해서 동적으로 브라우저에 올라가있는 데이터를 이용해서 DOM을 조작하게 된다.

장점으로는 서버에 요청이 줄어들기 때문에 좀 더 빠르고 서버쪽 부담이 줄어든다.

하지만 규모가 큰 웹 어플리케이션에서 코드가 복잡해지고, 재사용이 어려웠기 때문에 코드에 대한 구조화가 필요해졌고, 매번 새로운 페이지를 서버로부터 읽어오게 되면, 리소스를 서버로부터 다시 읽어오고, 브라우저 렌더링 다시 하기 때문에 성능저하가 문제되었다.

위와같은 문제를 해결하기 위해 등장하게 된 것이 SPA라는 개발패턴이다. Ajax의 확장판이라고 이해할 수 있다.

SPA 개발패턴은 URL 경로에 따라 자바스크립트로 화면을 동적으로 그리는 것을 말한다. 이때 웹 어플리케이션의 구조를 잡기 위한 프레임워크가 필요하게 되었는데, 이때 등장하게 된 프레임워크 중에 하나가 AngularJS이다.

* AngularJS : 단일 페이지 웹 어플리케이션 개발을 위한 자바스크립트 프레임워크

하지만, AngularJS는 규모가 큰 어플리케이션의 개발에 있어, 성능이슈를 보이고 복잡한 지시자 문법이 개발시에 큰 어려움을 줬다.
이러한 어려움을 해결하기 위해 등장하게 된 개념이 Web Component 기반의 개발이다.
이 Web Component는 Custom element, Shadow DOM, HTML Import, HTML template의 종합적인 개념으로, 웹 플랫폼 자체에서 재사용이 가능한 컴포넌트 기반으로 개발하는 것이 가능해졌다.

이를통해 기존의 성능이슈와 개발 생산성 문제를 해결할 수 있었다. 이때부터 기존의 프레임워크였던 AngularJS가 플랫폼인 Angular2 혹은 Angular4로 발전하게 되었다.

프레임워크에서 플랫폼으로 변화
Read more