Spa

1 minute read

SINGLE PAGE APPLICATION

한 페이지에 여러가지 인터랙티브한 UI를 포함한 어플리케이션이다.

장점

  • 사용자는 전체 화면의 새로고침(서버를 통한 전체 페이지 갱신)없이 빠르게 부분 UI의 갱신한다.
  • 향상된 UX를 뽐낸다.
  • 서버의 View 작업의 부담이 감소된다.

구현의 어려움

  • 클라이언트 렌더링 최적화 기술의 필요하다.
  • 모듈 관리가 복잡하다.
    • View - Model 역할과 의존성
    • Data binding처리
  • 상태 관리가 어렵다.
    • 전역변수
    • 서버와의 데이터 동기화
  • 라우팅 처리의 부담이 있다.
  • 초기 로딩에서 불필요한 자원의 로딩을 해야한다.

향상된 디자인

1. 디렉토리 구조 정의

계층을 나누고 각 계층은 동등한 수준으로 만든다.

  • /utils
  • /libs
  • /components
    • /modal
    • /calendar
  • /stores
    • /todos
    • /others
  • /views
    • /headers
    • /list

2. rendering 최적화

DOM 업데이트 영역의 최소화

변경을 탐지하고 그 부분의 업데이트만 실행한다.

img

동일한 결과에 대해서는 재사용

캐시를 사용하는 방법이다.

3. 더 빠른 초기 로딩

  • bundling 최적화

    • 공백제거, 변수/함수 이름 난독화. 중복 모듈 최소화
  • Server Side Rendering

    • 서버에서 정적인 UI를 완성. 클라이언트에서 이벤트 추가 (hydration)
    • fetch data (server) → render to HTML (server) → load code (client) → hydrate (client)
    • 클라/서버 모두 templating 해야 하는 부담.
  • SSR 을 넘어서 보자.(*)

    • Streaming HTML
    • selective hydrating
  • Code splitting

    async function getComponent() {
      const element = document.createElement('div');
      const { default: _ } = await import('lodash');
      
      element.innerHTML = _.join(['Hello', 'webpack'], ' ');
      
      return element;
     }
      
     getComponent().then((component) => {
       document.body.appendChild(component);
     });
    
    • 웹팩에서의 실행 example. (Lazy loading 을 사용하고 있음.)
    • https://medium.com/@anuhosad/code-splitting-in-webpack-with-dynamic-imports-4385b3760ef8

SPAs 애플리케이션 디자인

역할을 명확하게 해야 한다.

Model

비즈니스 로직이 없는 데이터 의 생성/변경/삭제

  • Testable model 인가?

View

데이터 조작이 없는 순수한 View 렌더링

  • 다른 데이터 구조에도 적용이 가능한가?

Model -> View의 단방향의 흐름제어 (unidirectional data flow)

img

  • View 간의 의존성이 없다.
  • 데이터 변경에 의해서 View가 변화한다.

Model 과 View의 관계

  • Data-binding
    • defineProperty
const fooView = { 
   render(data) {
      console.log("rendering data", data)
   }
}

const store = {
  _property1 : ''
};

const getter = () => `result is ${object1._property1}`;

const setter = (data) => { 
  store._property1 = data;
  //아마도 어떤 view 렌더링
  fooView.render(data);
}

Object.defineProperty(store, 'property1', {
  get: getter,
  set: setter
});

store.property1 = 77;
  • Proxy API
  • 구독형 방식 (Observer pattern) « 중요

Categories:

Updated: