업무 진행을 위해 Ember를 처음부터 배워보고 있는데 단순히 보고 Tutorial 을 따라한 것으로는 부족한 것 같아 정리 차 작성해보려 한다
모든 내용은 Ember 공식문서의 Tutorial과 예전 버전이긴 하지만 2022 ember beginners라는 외국 유튜브를 보고 적절히 섞어 작성하였다.
물론 Test에 관련된 부분은 적당히 제거했다
먼저 tutorial에서 만들어지는 웹사이트는 공식문석에 실제로 netlify를 통해 배포되어 있으니 직접 확인해 봐도 된다
Tutorial완성페이지 확인하기
먼저 Ember를 쉽게 사용하기 위한 CLI를 먼저 설치 했다
npm install -g ember-cli
설치가 잘 완료되었는지 확인해보자
ember --version
입력시 이런식으로 출력이 잘 되는지 확인해보자
EmberCLI 명령을 사용해서 새 프로젝트를 사용할 수 있다. create react-app
처럼 간단히 만들 수 있는 명령어인데 패턴을 살펴보자면
ember new <project-name>
으로 project-name 부분에 원하는 프로젝트 이름을 작성시 자동적으로 만들어 진다.
이때 공식문서에는 나와있는데로 뒤에 --lane en
을 통해 앱의 기본 언어를 영어롤 설정시키자. 웹 사이트의 접근성이 향상된다
ember new test-project --lang en
그렇다면 새로 생긴 test-project
폴더에 ember 프로젝트가 생긴 걸 확인할 수 있다.
이후 해당 폴더로 이동하여 npm start
를 실행할 경우 아주 기초적인 웹사이트가 하나 뜨는 걸 확인할 수 있다
주소는 http://localhost:4200 으로 기본 설정 되어 있다
처음 만들어질 때 파일 구조를 잘 살펴보면 아래와 같이 만들어져 있을 것이다.
test-project
├── .github
│ └── workflows
│ └── ci.yml
├── app
│ ├── components
│ │ └── .gitkeep
│ ├── controllers
│ │ └── .gitkeep
│ ├── helpers
│ │ └── .gitkeep
│ ├── models
│ │ └── .gitkeep
│ ├── routes
│ │ └── .gitkeep
│ ├── styles
│ │ └── app.css
│ ├── templates
│ │ └── application.hbs
│ ├── app.js
│ ├── index.html
│ └── router.js
├── config
│ ├── ember-cli-update.json
│ ├── environment.js
│ ├── optional-features.json
│ └── targets.js
├── public
│ └── robots.txt
├── tests
│ ├── helpers
│ │ └── index.js
│ ├── integration
│ │ └── .gitkeep
│ ├── unit
│ │ └── .gitkeep
│ ├── index.html
│ └── test-helper.js
├── .editorconfig
├── .ember-cli
├── .eslintcache
├── .eslintignore
├── .eslintrc.js
├── .gitignore
├── .prettierignore
├── .prettierrc.js
├── .stylelintignore
├── .stylelintrc.js
├── .template-lintrc.js
├── .watchmanconfig
├── README.md
├── ember-cli-build.js
├── package.json
├── package-lock.json
└── testem.js
16 directories, 37 files
하나씩 살펴보자면
ember에는 브라우저 URL과 통합되는 라우팅 시스템이 함께 제공된다.
예를 들면 우리가 localhost:4200/cart로 가려 한다면 실제 app/router.js
내부에서 카트경로를 검색 하기 시작한다.
// ...app/router.js
Router.map(function () {
this.route('cart');
});
이때 찾고있던 관련 항목을 찾으면 전체 앱이 어떻게 구성되어 있는지 빠르게 확인할 수 있도록 사이트맵 역할을 한다
이때 구동되는게 app/routes/cart.js
와 app/controllers/cart.js
이고 이를 통해 우리가 만든 app/templates/cart.hbs
가 템플릿 렌더링을 시작하게 된다.
라우팅에도 여러가지가 있는데
등이 있다.
하나씩살펴보자
먼저 ember에는 HCBS의 app/template/application.hbs
으로 시작되는 기본 애플리케이션 경로가 있다
이는 웹 앱의 시작점이기도 한데 최상위에 존재하는 react로 보자면 main이나 next의 최상위 layout이라고 생각하면 편할 것 같다.
모든 곳에서 쓰이는 부분을 이곳에 적용시키면 모두 적용된다.
Tutorial에선 nav-bar
를 application.hbs
에 적용한 다음 {{outlet}}
을 통해 하위 요소들을 렌더링 시킨다.
마치 react 최상위 요소에서 navbar
컴포넌트를 넣고 아래에 {children}
을 통해 각 페이지들이 렌더링 되도록 하는 것과 같았다
기본 경로이다.
ember cli를 통해 만들어 낼 수도 있고 직접 파일을 만들 수도 있는데 ember cli가 편한 방법 같기도 하다.
아직 ember에 대해 부족한 부분이 많아 CLI로 만드는게 좋은것인지 직접 만드는 게 좋은것인지 잘 모르겠지만 일단 Tutorial과 beginner 강의가 알려준대로 따라가보자.
ember g route clothes
// 또는
ember generate route clothes
이렇게 작성할 경우 저절로 template에 관련 파일이 생성되고 app/router.js
의 Router.map
함수 안에도 저절로 입력되어 있을것이다.
//...app/router.js
Router.map(function(){
this.route('clothes')
})
이러면 localhost:4200/clothes
로 이동할 경우 app/templates/clothes.hbs
에 입력한 요소들이 출력되게 된다.
중첩된 경로로 /clothes/t-shirt
와 같이 경로에 경로로 들어가는 경우이다.
예로 현재 clothes라는 옷 경로를 사용중인데 가장 가까운 하위 카테고리로 티셔츠로 들어가야 한다. 이때는 어떻게 구성을 하고 만들어야 할까??
생각보다 간단한데 이전 clothes
경로를 만들 때처럼 ember CLI를 사용하면 된다
ember g route clothes/t-shirt
clothes는 이미 만들어져 있고 그에 중첩된 경로를 /
를 통해 작성해주면 되는데 이러면 app/tmeplates
폴더에 clothes
라는 폴더가 생성되게 되고 그안에
그리고 router.js
내부 사항도 변경되게 되는데
Router.map(function(){
this.route('clothes',function(){
this.route('t-shirt')
})
})
처럼 변하게 된다.
상위 루트의 복사 기능 내에 루트 설정이 추가되는 것이다.(말이 번역본이라 어렵긴 한데 javascript 문법적으로만 보자면 Router
라는 class는 app/router.js
안에서 선언된 클래스로 EmberRouter
를 상속받고 있다.
그리고 Router 내부에서는 위에서 얘기했던 config
폴더의 환경변수 파일 environment.js
에서 locationtype
과 rootURL
을 덮어 씌우고 있다.
이후 Router
클래스의 map
메서드를 실행시키는데 map 메서드는 RouterDSL
이라는 콜백함수를 받는다. 해당 콜백함수 안에는 route
라는 메서드가 존재하고 route
메서드는 우리가 연결한 url
경로 이름을 첫번째 매개변수로 받고 option
(경로 이름과 파일 이름을 서로 다른걸 사용하고 싶을때)과 또 같은 RouterDSL
을 콜백함수로 가지는 콜백함수를 옵셔널로 실행할 수 있다.
여기서 중첩 라우팅일 경우 route안에 route로 중첩해서 사용하는 방식으로 this.route
를 통해 clothes
경로를 만든뒤 바로 위에서 설명한 옵셔널한 콜백함수를 다시 작성하여 this.route
t-shirt
를 넣는것이다.
이후 app/templates/clothes/t-shirt
로 들어가면 t-shirt
에서 작성한 HTML 요소들이 보일 것이다.
각 슬래시 마다 기본적으로 보여주는 페이지들이 있는데 이를 index를 통해 관리 할 수 있다.
예를 들어 clothes
라는 경로로 이동했을 때 물론 clothes.hbs
라는 파일 내에서도 작성할 수 있지만 무언가 기본적으로 표시되고 싶은 걸 파일로 나누고 싶다면 index.hbs
를 templates/clothes
폴더안에 생성할 경우 자동적으로 clothes.hbs
의 {{outlet}}
부분에 표시된다.
이때 경로를 clothes/t-shirt
로 들어갈 경우 index.hbs
에서 작성한 요소는 표기되지 않고 t-shirt.hbs
에서 작성한 요소만 표기되며
/clothes
만 들어갈 경우 clothes.hbs
의 {{outlet}}
부분에 index.hbs
의 요소들이 자동적으로 표기되게 된다
각 라우팅들에서 표시될 수 있는 기본 값이라고 생각하면 편할 것 같다.
동적 라우팅으로 동적실행 또는 동적 세그먼트이다
주로 사용 되는게 게시물이나 상품의 ID
를 경로에 넣는 것이 있다. item/123
이면 123번의 item을 보여달라는 것과 같다
지금 item/123
의 경우 URL의 마지막 세그먼트 인스턴트인데 한번만들어보자
똑같이 emberCLI를 통해 만든다면
ember g route item
으로 한번 만들어보자 이경우 위에서 router.js
에 새로 만들어지는 것처럼
Router.map(function(){
this.route('clothes',function(){
this.route('t-shirt')
})
this.route('item')
})
가 생성되는데 조금 변경시켜보자
Router.map(function(){
this.route('clothes',function(){
this.route('t-shirt')
})
this.route('item',{path:"/item/:item_id"})
})
아까 말했던 옵셔널로 주어지는 인자중에 표기와 이름을 다르게 하는 옵션인자를사용해 {path:"/item/:item_id"}
를 통해 실제 url은 item/
과 마지막에 :item_id
가 동적 세그먼트로 들어올수 있도록 한다
이후 실제로 /items/1
으로 경로를 이동해서 실제테스트 해보자.
화면은 잘 뜨는데 그럼 동적 라우팅한 값은 어디서 얻을 수 있을까?
app/routes
폴더로 이동해보면 emberCLI를 통해 generate
로 만들 때 함께 만들어진 clothes.js
와 item.js
가 자동적으로 만들어져 있을 것이다.
이때 item
에 대해서 동적으로 받는 것에 대한 모델링이 필요함으로
import Route from '@ember/routing/route'
export default class ItemRoute extends Route {
model(params) {
const {item_id} = params;
return item_id;
}
}
이렇게 작성하면 이젠 정상적으로 렌더링 되는 것을 확인할 수 있다
그럼 이 모델에서 return
한 item_id
는 어디서 어떻게 받을 수 있을까? 하고 의문을 가지는데 이는 item.hbs
에서 사용할 수 있다
// app/templates/item.hbs
<h1> {{this.model}} </h1>
이렇게 작성할 경우 this.model
부분이 아까 return item_id
부분이 되게 된다.
이를 살펴볼때 위에서 설명한 ember의 라우팅 부분에서 마지막 hbs
파일에 도달해서 렌더링 하기 전에 route폴더와 controller 폴더에서 해당되는 js들을 실행시키고 오는 것 같다.
마치 class형 react를 했을 때 처럼 사용되는 함수들은 route폴더 안의 js파일에 메서드들로 작성하고 실행은 hbs에서 {{this.함수명}}
으로 실행시키는 것이다.
이때 주의할 것으로 실제로 에러를 겪었던 부분인데 이름의 중요성이다. item
이라는 경로를 사용 했는데 templates에서도 item.hbs
여야 하고 routes에서도 item.js
그리고 실행되는 class도 ItemRoute로 대소문자까지 잘 지켜줘야 실행되는 걸 볼 수 있다.
때문에 직접 만들 경우 오타의 문제가 생길지 모르니 emberCLI를 사용하는 게 더 좋은 것 같다는 생각이 든다
우리가 흔히 보는 에러페이지로 next 등에는 404.js
사용하는 것처럼 사용할 수 있다.
예를 들어 우리가 지정하지 않은 경로로 사용자가 이동 하였을 때 사용자는 개발자가 아니기에 콘솔창을 확인해 보지 않는다.
이로 인해 비어 있는 페이지가 사용자를 반기게 되고 사용자는 페이지가 로딩중인지 에러가 났는지 전혀 알 수가 없는 상태가 된다.
이러면 유저 입장을 전혀 고려하지 않은 설계가 됨으로 이러한 에러 페이지는 필수라고 생각한다.
ebmerCLI를 통해 만들어보자
ember g route not-found
이후 작성된 경로부분을 수정한다.
Router.map(function(){
this.route('clothes',function(){
this.route('t-shirt');
});
this.route('item',{path:"/item/:item_id"});
this.route('not-found',{path:'/*path'});
});
이렇게 저장할 경우 허용되지 않은 URL로 들어간다 하더라도 콘솔 오류는 사라지고 application.hbs
에서 작성되어 있는 요소는 그대로 출력되는 것을 확인할 수 있다.
이후 아래엔 not-found.hbs
에 작성한 에러임을 알리는 요소들이 출력되는 것을 볼 수 있다.
이에 에러 페이지에 다시 되돌아가는 버튼을 만들어 놓는다면 사용자 측면에서 이 페이지가 에러고 다시 돌아가면 되겠다라는걸 명확하게 보여줄 수 있게된다.
여기까지가 ember에 있는 라우팅 시스템이고 더욱 자세하게 알아본다면 라우팅 시스템 안에 리디렉션과 전환 방지나 재시도 등 여러가지가 있는데 tutorial이 끝나면 또 하나씩 정리 해봐야겠다.