Hello Enact #1 - 기본

Hello Enact #1 - 기본

앞으로 4회에 걸쳐 Hello Enact! 앱을 만들면서 기본을 배워보는 시간을 갖도록 하겠습니다. 1편에서 우리는 모듈을 만들고 앱이 어떻게 DOM에 렌더하는지 살펴보겠습니다. 그리고 앱을 패키징하고 실행해 보겠습니다.
아직 Enact 를 설치하지 않으셨다면, Enact 개발환경 설정 포스팅을 먼저 읽고, 본 튜토리얼을 따라하시기 바랍니다.

사전 준비

아래 명령으로 hello enact 프로젝트를 생성합니다.

enact create tutorial-hello-enact

src/views/MainPanel.js 파일은 본 튜토리얼에서 사용하지 않으므로 삭제합니다.

App module 생성

우리가 만드는 앱의 시작 위치는 ./src/index.js 에 있습니다. App 컴포넌트의 홈이 될 새로운 모듈을 만들겠습니다.

CommonJS의 모듈은 하나의 파일을 직접 참조하거나 하나의 파일로 해석할 수 있는 디렉토리를 참조할 수 있습니다. Node.js 는 모듈 참조를 위한 룰을 정의하고 있습니다. webpack 은 모듈 해석을 커스터마이즈 하기위한 설정을 갖고 있습니다.

Enact는 앱을 위한 모듈을 다음과 같은 방법으로 생성하기를 권장합니다:

  • 모듈을 위한 자신의 디렉토리를 만들고 그 안에 모듈을 위치시키세요. – e.g. ./src/App
  • 주요 로직과 동일한 이름의 소스파일 이름을 사용하세요. – e.g. ./src/App/App.js
  • package.json 파일을 디렉토리 안에 포함시키고, main 프라퍼티가 모듈 js파일을 가르키도록 하세요.

모듈의 package.json 파일

대부분의 모듈에서 package.json 파일은 main 프라퍼티만 사용 합니다. 이 파일은 package descriptor file에서 정의하는 어떤 프라퍼티라도 가질 수 있습니다.

./src/App/package.json 파일을 만들고 내용을 다음과 같이 채워 넣읍시다.

 {
  "main": "App.js"
 }

모듈의 소스파일

이제 실제 코드를 작성해 보겠습니다. ./src/App/App.js 파일을 생성하고 아래와 같이 우리의 첫번째 모듈을 만듭니다:

 import React from 'react';
 
 const App = function () {
  return (
   <div>
    Hello, Enact!
   </div>
  );
 };
 
 export default App;
 export {App};

차근차근 한줄씩 풀어보도록 하겠습니다.

우리는 enactCLI 가 생성해준 코드의 대부분을 제거했습니만, 개념을 설명하면서 점진적으로 하나씩 추가할 것입니다.

import 와 React

첫번째 단계는, 이 컴포넌트에 필요한 모듈을 import 하는 것입니다. import 는 ES6 모듈에서 새롭게 제공하는 기능입니다.(spec참고).

 import React from 'react';

Enact 는 Facebook의 React 라이브러리 기반으로 구축되어 있습니다. react모듈은 컴포넌트를 생성하고 조합하는데 필요한 기능을 제공합니다. 렌더링은 다른 모듈인 react-dom에 의해서 처리됩니다. 이 부분은 이후 다시 설명하겠습니다.

App 컴포넌트

이미 눈치 채셨겠지만, App도 컴포넌트 입니다. 가장 심플한 타입의 React 컴포넌트는 Stateless Function 입니다. SFC라고 줄여서 부릅니다. props 오브젝트를 받아 React element를 리턴합니다. 우리의 첫번째 버전 Hello Enact 에서는 argument를 생략하고, div DOM 노드에 인사말을 렌더 하겠습니다.

 const App = function () {
  return (
   <div>
    Hello, Enact!
   </div>
  );
 };

React는 두 가지 타입의 컴포넌트를 지원합니다 – ES6 classes 와 Stateless Functions 입니다. 두 가지 모두 나중에 자세히 다루겠습니다.

const vs let

constlet 은 ES6 (spec) 에서 지원하는 변수를 정의하는 새로운 표현입니다. const는 참조 변경이 불가능한 변수를 생성하고 (read-only reference), let은 참조 변경이 가능한 변수를(mutable reference) 생성합니다. 둘 다 블럭단위 스코프 입니다. 기존에 사용하던 var는 글로벌 혹은 함수단위 스코프 입니다.

Enact 에서는, constdefault로 사용하고, reference를 변경할 필요가 있을 경우에만 let을 사용하기를 권장합니다.

  const App = function () {

이 예제에서 앱 컴포넌트를 reder 하는 함수를 참조하는 const App을 정의하고 있습니다.

컴포넌트 구성하기

React 에서 모든 컴포넌트의 render method는 단독 루트 엘리먼트나 null을 리턴해야 합니다. (React 16 이후부터는 단독 엘리먼트가 아니어도 됩니다. 상위에 <div>로 감싸는 귀찮은 짓을 더이상 안해도 됩니다. 상세내용)
루트 엘리먼트는 <div>와 같은 DOM 노드 이거나 커스텀 컴포넌트 이어야 합니다(곧 우리가 만들 겁니다). 루트 엘리먼트는 DOM 노드나 커스컴 컴포넌트외에도 문자열이나 숫자를 포함할 수 있습니다.

우리의 Hello, Enact! 앱은 <div>를 루트 엘리먼트로 하고 하위에 Hello, Enact! 문자열을 갖습니다.

  return (
   <div>
    Hello, Enact!
   </div>
  );

return 문 안에 <div>가 들어감 으로써 더이상 유효한 자바스크립트 문법이 아님을 발견하였을 겁니다. 이 HTML처럼 생긴 문장은 React 에서 제안하는 자바스크립트 구문 확장인 JSX입니다. 브라우저에서 JSX를 실행 가능하게 만들려면 자바스크립트로 변환을 해야 합니다. Enact 에서는 webpackbabel을 사용하여 빌드 프로세스 중에 처리를 합니다.

App 내보내기

이제 우리의 컴포넌트를 정의 했으므로, 마지막 단계는 이것을 모듈로 내보내서 사용할 수 있도록 하는 것 입니다. 이것은 ES6 모듈 스펙의 새로운 기능인 export 명령문을 사용하여 수행됩니다. default export, 명명된 export 혹은 둘 다로 export 할 수 있습니다.

대부분의 경우, 각 모듈은 default export 대상이 될 단일 컴포넌트를 포함합니다. 추가 컴포넌트, 함수, 상수등을 export 할 수도 있습니다.

 export default App;
 export {App};

명명된 export에 대한 추가사항

Enact 프레임워크 내에서 default export는 CommonJS 사용자와의 호환성을 위해 명명된 export 도 포함합니다. 만약, default export 만 있으면, require()를 사용하는 개발자는 아래와 같은 약간 어색한 구문을 써야 합니다.

var App = require('./src/App').default

명명된 export를 포함하면, 보다 직관적인 구문을 사용할 수 있습니다.

var App = require('./src/App').App

App 렌더링

App 컴포넌트가 준비가 되면 DOM에 렌더링할 수 있습니다. 렌더링 로직은 앱의 시작점인 ./src/index.js에 존재합니다. 전체 코드는 다음과 같습니다.

./src/index.js

 import React from 'react';
 import {render} from 'react-dom';
 
 import App from './App';
 
 let appElement = (<App />);
 
 // In a browser environment, render instead of exporting
 if (typeof window !== 'undefined') {
  render(
   appElement,
   document.getElementById('root') // provided by Enact's HTML template
  );
 }
 
 export default appElement;

dev 툴에서 생성해 주는 index.jsApp 컴포넌트를 DOM에 렌더링 하거나, 다른 컴포넌트에서 import 할 수 있게 합니다.

React 와 ReactDOM

우리의 App 모듈에서는 React import와 함께 새로운 모듈인 react-dom을 import 하고 있습니다. ReactDOM은 React 컴포넌트 트리를 DOM트리로 변환해 줍니다. 대부분 render() method를 사용합니다.

 import React from 'react';
 import {render} from 'react-dom';

중괄호로 감싸진 {render}react-dom에서 명명된 내보내기를 import 하는데 사용됩니다. 또는 모듈 전체를 ReactDOM으로 가져와서 그 객체의 render()를 호출함으로써 동일한 결과를 가져올 수 있습니다.

 import ReactDOM from 'react-dom';
 ReactDOM.render( ... );

우리가 만든 App import 하기

다음으로, 우리가 만든 App 모듈을 가져오겠습니다. 외부 모듈과 구분하기 위하여 내부 모듈은 상대 경로('./App')를 사용합니다. 앱의 package.json에 정의한 내용을 기반으로 하여 소스파일 전체 경로 대신에 디렉토리 이름을 사용할 수도 있습니다.

   import App from './App';

render()

마지막으로, render()를 사용하여 우리의 App을 렌더링 합니다. 이 함수는 React 엘리먼트와 렌더링할 DOM을 파라미터로 받습니다. 우리는 JSX를 다시 사용하여 App 컴포넌트를 위한 React 엘리먼트를 만들고, getElementById함수를 사용하여 DOM node를 반환합니다.
Enact 가 빌드하는 동안 기본 HTML파일을 생성합니다. body에는 <div id="root"></div> 문장이 포함될 것입니다. 우리의 앱은 여기에 렌더링 될 것 입니다.

 render(
  <App />,
  document.getElementById('root')
 );

처음 접해보는 분은 우리가 HTML을 엘리먼트에 작성하는 것 처럼 보일 수 있습니다. 사실 그게 정확히 우리가 한 일입니다. JSX는 마크업에 삽입할 수 있는 HTML 엘리먼트처럼 우리의 App 컴포넌트를 취급합니다.

App 실행하기

Enact는 여러가지 npm스크립트를 제공하여 앱 작업을 쉽게 처리하도록 도와줍니다.

  • npm run pack - ./dist 디렉토리에 앱코드를 번들링 합니다.
  • npm run pack-p - ./dist 디렉토리에 앱코드를 미니파이하고 소스맵 없이 번들링 합니다.
  • npm run serve - 앱을 메모리에 번들링 하고 8080포트에서 http 서버를 시작합니다. 그 위에 번들링된 앱을 실행해 줍니다. 소스 파일이 변경 될 때마다 자동으로 다시 빌드되고 브라우저는 새로 고침됩니다. (webpack-dev-server를 사용합니다).
  • npm run clean - ./dist 와 그 내용을 지웁니다.

지금까지 잘 따라오셨다면, npm run serve 명령이 정상적으로 실행 되어야 합니다. 나머지 가이드를 진행하면서 새로운 변경사항을 저장할 때 마다 앱이 다시 로드 되는것을 볼 수 있습니다.

끝!

긴 글 읽고 따라와 주시느라 수고하셨습니다! 이제 우리는 보일러 플레이트 Enact App을 구축했고, npm run serve 명령을 사용하여 실행했습니다. 다음 시간에는 CSS모듈을 사용하여 스타일을 추가하는 방법을 알아 보겠습니다. Hello Enact!의 전체 코드는 아래 링크를 참조하세요.

링크

댓글

이 블로그의 인기 게시물

Enact 프레임워크를 오픈합니다.

Enact 개발환경 설정

Enact 컴포넌트의 호환