일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- hybride
- 다이빙
- 젤다의전설
- window
- 페오엑
- 어드벤스
- 공략
- window10
- Front-end
- 게임
- WebView
- 여행
- 오픈워터
- ubuntu
- Linux
- 뱀파이어서바이벌
- 야생의숨결
- 취미
- psql
- poe2
- 개발툴
- JavaScript
- 씨홀스
- 스쿠버다이빙
- 세부
- guide
- PostgreSQL
- JS
- 엘든링
- docker
- Today
- Total
Rianshin
Angular Style Guide @ John_papa 번역 본문
- 커뮤니티의 놀라움과 신용
- 당신은 결코 혼자서 아닙니다! Angular 커뮤니티는 자신의 경험을 공유 할 열정적 인 큰 집단입니다. 실제로 친구이자 Angular의 전문가이기도한 Todd Motto 내가 공동으로 많은 스타일과 규약을 정리했습니다. 일부 의견이 분분했지만 대체로 합의 할 수있는 것이 었습니다.그의 접근 방식과 본 스타일의 비교를 위해 꼭 Todd 's guidelines 을 확인하는 것이 좋습니다.여기서 소개하는 많은 스타일은 수많은 페어 프로그래밍 세션 Ward Bell 과 나 자신이 이미 가지고 있던 생각 때문입니다. 항상 의견이 일치하는 것은 아니다 만, 친구의 Ward는이 가이드의 궁극적 인 발전에 크게 공헌 해주었습니다.
- 샘플 앱에서 스타일보기
- 이 가이드는 "무엇을", "왜", "어떻게"실시하면 좋을 것인가라고 설명을하고 있지만 맞게 실천보고가는 것이 이해에 도움이됩니다. 본 가이드는 스타일과 패턴에 따라 샘플 어플리케이션을
modular
디렉토리 에 제공하고 있습니다. 여기에서 자유롭게 취득 clone이나 fork를 받고 상관하지 않습니다. 또한 readme 수행을위한 지침 도 있습니다.
- 이 가이드는 "무엇을", "왜", "어떻게"실시하면 좋을 것인가라고 설명을하고 있지만 맞게 실천보고가는 것이 이해에 도움이됩니다. 본 가이드는 스타일과 패턴에 따라 샘플 어플리케이션을
- 번역
- 번역문은 여기서 확인이 가능하다.(한국어는 왜 없냐 근데..ㅡㅡ우씽..)
- 차례
- Single Responsibility -
- IIFE
- Modules
- Controllers
- Services
- Factories
- Data Services
- Directives
- Resolving Promises for a Controller
- Manual Annotating for Dependency Injection
- Minification and Annotation
- Exception Handling
- Naming
- Application Structure LIFT Principle
- Application Structure
- Modularity
- Startup Logic
- Angular $ Wrapper Services
- Testing
- Animations
- Comments
- JSHint
- JSCS
- Constants
- File Templates and Snippets
- Yeoman Generator
- Routing
- Task Automation
- Filters
- Angular Docs
- Contributing
- License
- 파일마다 하나의 구성 요소를 정의하십시오.다음 예제는
app
모듈과 종속 컨트롤러의 정의와 공장의 정의는 모두 같은 파일에 정의되어 있습니다.
1
2
3
4
5
6
7
8
9
10
| /* avoid */ angular
.module('app', ['ngRoute'])
.controller('SomeController', SomeController)
.factory('someFactory', someFactory);
function SomeController() { }
function someFactory() { }
| cs |
- 구성 요소 단위로 파일로 분할합니다.
1
2
3
4
5
6
| /* recommended */ // app.module.js angular
.module('app', ['ngRoute']);
| cs |
1
2
3
4
5
6
7
8
| /* recommended */ // someController.js angular
.module('app')
.controller('SomeController', SomeController);
function SomeController() { }
| cs |
1
2
3
4
5
6
7
8
| /* recommended */ // someFactory.js angular
.module('app')
.factory('someFactory', someFactory);
function someFactory() { }
| cs |
- Angular 구성 요소를 즉시 함수식 (Immediately Invoked Function Expression : IIFE)으로 감싸주세요.
- 이유:
- IIFE을 이용하면 변수는 전역으로되지 않습니다. 이에 따라 변수가 글로벌 스코프에서 기대 이상으로 오래 생존 해 버리는 것을 막을 수가 있습니다. 또한 변수끼리의 충돌도 피할 수 있습니다.
- 코드를 Minify하여 하나의 파일에하고 프로덕션 서버에 배포 할 때 변수의 충돌이나 다수의 글로벌 변수의 존재가 문제를 일으킬지도 모릅니다. IIFE은 파일마다 범위를 가지고 있기 때문에 이러한 문제를 방지 할 수 있습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| /* avoid */ // logger.js angular
.module('app')
.factory('logger', logger);
// logger function is added as a global variable function logger() { }
// storage.js angular
.module('app')
.factory('storage', storage);
// storage function is added as a global variable function storage() { }
| cs |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
| /** * recommended * * no globals are left behind */ // logger.js (function() {
'use strict';
angular
.module('app')
.factory('logger', logger);
function logger() { }
})();
// storage.js (function() {
'use strict';
angular
.module('app')
.factory('storage', storage);
function storage() { }
})();
| cs |
- 참고 : 간결하게하기 위해서 다음에 이어지는 코드 예제에서는 IIFE 구문을 생략시켜주십시오.
- 참고 : 테스트 코드는 정규 표현식과 단위 테스트를위한 유효한 helper 함수처럼 사적인 멤버에 자주 액세스하지만 IIFE는 그 접근에 방해가됩니다. 그러나 액세스 가능한 멤버 통해 테스트를하거나 독립적 인 구성 요소를 통해 이들을 공개되는 것을 테스트 할 수 있습니다. 예를 들어, helper 함수 정규 표현식 또는 상수를 Angular 팩토리와 상수로 준비 해 버리는 방법이 있습니다.
서브 모듈 분리기를 이용한 독특한 명명 규칙을 사용하십시오.
왜? : 독특한 이름 충돌을 방지 할 수 있습니다. 분리 모듈 및 서브 모듈의 계층 구조를 정의하는 데 도움이됩니다. 예를 들어,app
는 루트가되는 모듈이며,app.dashboard
또는app.users
은app
과 의존하는 모듈지도 모릅니다.
세터를 사용하여 변수를 사용하지 않고 모듈을 정의하십시오.
왜? : 1 파일 1 구성 요소의 원칙 하에서는 모듈의 선언에서 변수가 필요한 경우는 매우 드뭅니다.
1
2
3
4
5
6
7
| /* avoid */ var app = angular.module('app', [
'ngAnimate',
'ngRoute',
'app.shared',
'app.dashboard'
]);
| cs |
1
2
3
4
5
6
7
8
| /* recommended */ angular
.module('app', [
'ngAnimate',
'ngRoute',
'app.shared',
'app.dashboard'
]);
| cs |
- 모듈을 이용할 때는 변수를 사용하는 것을 피하고 대신 게터를 사용한 체인을 사용하십시오.
- 이유 :
- 가독성 높은 코드입니다 변수의 충돌이나 누수를 방지 할 수 있습니다.
1
2
3
4
5
| /* avoid */ var app = angular.module('app');
app.controller('SomeController', SomeController);
function SomeController() { }
| cs |
1
2
3
4
5
6
| /* recommended */ angular
.module('app')
.controller('SomeController', SomeController);
function SomeController() { }
| cs |
- 한 번만 set하여 다른 인스턴스에서 모든 get하십시오.
- 이유
- 모듈은 한 번 생성 된 이후에는 취득 만 수행해야합니다.
- Use `angular.module('app', []);` to set a module.
- Use `angular.module('app');` to get a module.
1
2
3
4
5
| /* avoid */ angular
.module('app')
.controller('Dashboard', function() { })
.factory('logger', function() { });
| cs |
1
2
3
4
5
6
7
8
| /* recommended */ // dashboard.js angular
.module('app')
.controller('Dashboard', Dashboard);
function Dashboard() { }
| cs |
1
2
3
4
5
6
| // logger.js angular
.module('app')
.factory('logger', logger);
function logger() { }
| cs |
전형적인 $ scope를 사용한 controller
구문보다controllerAs
을 사용하라.- 이유:
- 전혀 새로운 Controllers가 생성되면 하나의 새로운 인스턴스가 생성됩니다.
controllerAs
구문은전형적인 $ scope를 사용한 controller
구문보다 JavaScript의 생성자에 가까운 것입니다. - 뷰에서 “dotted"에 의한 바인딩이 용이 해져 (예를 들어,
name
대신customer.name
이되는 것으로) 다양한 상황에 대응 가능 해져 가독성이 높아집니다. 또한 “dotted"을 사용하지 않을 경우 발생할 수있는 참조의 문제를 피할 수 있습니다. - 중첩 된 컨트롤러를 사용한 뷰에서
$ parent
의 호출을 피하는 데 도움이됩니다.
- 전혀 새로운 Controllers가 생성되면 하나의 새로운 인스턴스가 생성됩니다.
1
23 4 5 | <!-- avoid -->
<div ng-controller="Customer">
{{ name }}
</div>
| cs |
1
2
3
4
| <!-- recommended -->
<div ng-controller="Customer as customer">
{{ customer.name }}
</div>
| cs |
전형적인 $ scope를 이용한 컨트롤러
의 구문보다controllerAs
구문을 사용하십시오.controllerAs
구문을 이용하여 $ scope에 바인딩되는 컨트롤러의 내부에서this
를 사용하십시오.- 이유 :
controllerAs
은$ scope
의 당의 구문 ( 설탕 구문? 문법)이되므로,$ scope
가 계속 뷰에 바인딩됩니다. 따라서$ scope
방법도 사용할 수 있습니다.- 컨트롤러 내부에서
$ scope
방법을 이용하고 싶은 경우에 그것을 자체를 피하는 것이 좋은지 혹은 팩토리로 이동하는 것이 좋은 수 있습니다. 그런 때 컨트롤러에 넣어 버리고 싶은 유혹을 멀리 유지에 도움이됩니다. 팩토리에서 $ scope를 사용하거나 필요한 경우에 한하여 컨트롤러에서$ scope
를하는 것을 고려하십시오. 예를 들어,$ emit
과$ broadcast
또는$ on
을 사용하여 이벤트 publish 및 subscribe 할 때에는 그 구현을 공장으로 이동하거나 컨트롤러에서 호출 등의 형태를 고려하십시오.
1
23 4 5 6 7 8 | / * avoid * / function Customer ( $ scope ) { $ scope. name = {}; $ scope . sendMessage = function () {}; } | cs |
1
2
3
4
5
6
| /* recommended - but see next section */ function Customer() {
this.name = {};
this.sendMessage = function() { };
}
| cs |
controllerAs
구문을 이용할 때는this
를 캡처 한 변수를 사용하십시오. 뷰 모델을 나타내는vm
같은 일관성있는 이름을 선택하십시오.- 이유 :
this
키워드는 문맥에 따라 변화하기 때문에 컨트롤러 함수에서 사용되는 경우에는 컨텍스트가 변경 될 수도 있습니다.this
의 문맥을 캡처하여 이러한 문제를 피할 수 있습니다.
1
2
3
4
5
| /* avoid */ function Customer() {
this.name = {};
this.sendMessage = function() { };
}
| cs |
1
2
3
4
5
6
| /* recommended */ function Customer() {
var vm = this;
vm.name = {};
vm.sendMessage = function() { };
}
| cs |
- 참고 : 코멘트를 코드의 상단에 넣는 것으로 jshint 의 warnings를 피할 수 있습니다. 그러나 함수가 어퍼 케이스의 경우에는 필요하지 않습니다. 약관으로 그것은 생성자이며, Angular는 컨트롤러에 해당됩니다.
1
2
| /* jshint validthis: true */ var vm = this;
| cs |
- 참고 :
controller as
를 이용한 컨트롤러에서 watch를 만들 때 다음 구문vm *
멤버를 watch(?) 수 있습니다. (digest 사이클에서 부하가 걸리게 조심 watch를 만듭니다.)
controller as
, you can watch the vm.*
member using the following syntax. (Create watches with caution as they add more load to the digest cycle.))
1
| <input ng-model="vm.title"/>
| cs |
1
2
3
4
5
6
7
8
9
| function SomeController($scope, $log) {
var vm = this;
vm.title = 'Some Title';
$scope.$watch('vm.title', function(current, original) {
$log.info('vm.title was %s', original);
$log.info('vm.title is now %s', current);
});
}
| cs |
- 바인딩 멤버를 컨트롤러의 선두에 알파벳 순서로 배열하고 컨트롤러의 코드에 분산시키지 마십시오.
- 이유 :
- 바인딩 멤버를 선두로 작성하면 가독성이 올라 컨트롤러의 어떤 멤버가 바인딩 된 뷰에서 사용되는지를 즉시 확인할 수 있습니다.
- 인라인 익명 함수를 설정하는 것은 쉽지만, 한 줄 이상의 함수일 경우 가독성이 떨어집니다. 바인딩 멤버 아래 함수를 정의합니다 (함수는 철거(?) 됨) 구현의 상세는 아래로 이동합니다. 이렇게하면 바인딩하는 멤버를 앞에 둔 채 가독성을 높일 수있을 것입니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| /* avoid */ function Sessions() {
var vm = this;
vm.gotoSession = function() {
/* ... */
};
vm.refresh = function() {
/* ... */
};
vm.search = function() {
/* ... */
};
vm.sessions = [];
vm.title = 'Sessions';
| cs |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| /* recommended */ function Sessions() {
var vm = this;
vm.gotoSession = gotoSession;
vm.refresh = refresh;
vm.search = search;
vm.sessions = [];
vm.title = 'Sessions';
////////////
function gotoSession() {
/* */
}
function refresh() {
/* */
}
function search() {
/* */
}
| cs |
- 참고 : 만약 함수가 한 라이너이면 가독성에 영향이없는 한 위에 올려 놓으면하는 것을 고려하십시오.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| /* avoid */ function Sessions(data) {
var vm = this;
vm.gotoSession = gotoSession;
vm.refresh = function() {
/**
* lines * of * code * affects * readability */ };
vm.search = search;
vm.sessions = [];
vm.title = 'Sessions';
| cs |
1
2
3
4
5
6
7
8
9
| /* recommended */ function Sessions(dataservice) {
var vm = this;
vm.gotoSession = gotoSession;
vm.refresh = dataservice.refresh; // 1 liner is OK
vm.search = search;
vm.sessions = [];
vm.title = 'Sessions';
| cs |
- 구현의 상세를 숨기기 위해 함수 선언을 사용하십시오. 또한 바인딩되는 멤버를 앞에두십시오. 컨트롤러에서 함수를 바인딩 할 때 그 함수가 파일의 뒤에 나오는 함수 선언을 가리 키도록합니다. 이것은 "Bindable Members Up Top"절과 직접 대응하고 있습니다. 자세한 내용은 이 포스트 를 참조하십시오.
- 이유 :
- 바인딩 멤버를 선두로 작성하여 가독성이 올라 컨트롤러의 어떤 멤버가 바인딩 된 뷰에서 사용되는지를 즉시 확인할 수 있습니다 (위와 동일).
- 함수의 구현 세부 사항을 파일의 후방에 배치하여 view에서 복잡성을 제거하고 중요한 것이 파일의 시작 부분에서 보이게됩니다.
- 함수 선언이 철거되기 때문에 (함수이며 쉬운) 함수를 선언하기 전에 이용하고 버리는 우려가 없습니다.
var b
앞에var a
를 이동하는 함수 선언이a
가b
에 의존해서 코드가 손상 버릴 염려 할 필요는 결코 없습니다.- 함수는 순서가 중요합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
| /** * avoid * Using function expressions. */ function Avengers(dataservice, logger) {
var vm = this;
vm.avengers = [];
vm.title = 'Avengers';
var activate = function() {
return getAvengers().then(function() {
logger.info('Activated Avengers View');
});
}
var getAvengers = function() {
return dataservice.getAvengers().then(function(data) {
vm.avengers = data;
return vm.avengers;
});
}
vm.getAvengers = getAvengers;
activate();
}
| cs |
- 중요한 일이 계속 위의 예는 아로 흩어져(?) 있는 것에 주목하십시오. 아래의 예는 중요한 것이 선두에있는 것을 알 수 있습니다. 예를 들어,
vm.avengers
과vm.title
가 컨트롤러에 바인딩되어 있습니다. 그리고 구현 세부 사항이 아래에 있습니다. 이에 따라 가독성이 올라 있습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
| /* * recommend * Using function declarations * and bindable members up top. */ function Avengers(dataservice, logger) {
var vm = this;
vm.avengers = [];
vm.getAvengers = getAvengers;
vm.title = 'Avengers';
activate();
function activate() {
return getAvengers().then(function() {
logger.info('Activated Avengers View');
});
}
function getAvengers() {
return dataservice.getAvengers().then(function(data) {
vm.avengers = data;
return vm.avengers;
});
}
}
| cs |
- 서비스와 팩토리에 위임하여 컨트롤러 내의 로직을 지연시켜주십시오.
- 이유:
- 로직이 서비스 내에 배치되어 함수를 통해 이용 가능하게되면 여러 컨트롤러에 의해 재사용 될지도 모릅니다.
- 단위 테스트에서 서비스의 논리는 쉽게 분리 할 수 있습니다. 따라서 컨트롤러 호출 로직을 쉽게 모의 화가 수 있습니다.
- 의존성을 제거 컨트롤러에서 구현 세부 사항을 숨길 수 있습니다.
- 컨트롤러를 날씬하게 정돈하고, 초점시켜주십시오.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
| /* avoid */ function Order($http, $q, config, userInfo) {
var vm = this;
vm.checkCredit = checkCredit;
vm.isCreditOk;
vm.total = 0;
function checkCredit() {
var settings = {};
// Get the credit service base URL from config
// Set credit service required headers
// Prepare URL query string or data object with request data
// Add user-identifying info so service gets the right credit limit for this user.
// Use JSONP for this browser if it doesn't support CORS
return $http.get(settings)
.then(function(data) {
// Unpack JSON data in the response object
// to find maxRemainingAmount
vm.isCreditOk = vm.total <= maxRemainingAmount
})
.catch(function(error) {
// Interpret error
// Cope w/ timeout? retry? try alternate service?
// Re-reject with appropriate error for a user to see
});
};
}
| cs |
1
2
3
4
5
6
7
8
9
10
11
12
13
| /* recommended */ function Order(creditService) {
var vm = this;
vm.checkCredit = checkCredit;
vm.isCreditOk;
vm.total = 0;
function checkCredit() {
return creditService.isOrderTotalOk(vm.total)
.then(function(isOk) { vm.isCreditOk = isOk; })
.catch(showServiceError);
};
}
| cs |
- 하나의 뷰에 하나의 컨트롤러를 정의하고 다른 뷰에서 재사용을 시도하지 마십시오. 대신 재사용 가능한 로직을 팩토리로 이동하여 컨트롤러를 간단하게 뷰에 포커스시켜주십시오.
- 이유 :
- 여러 뷰를 가진 컨트롤러를 재사용하는 것은 취약하며, 대규모 응용 프로그램에서 안정성을 확보하기 위해서는 높은 범위의 엔드 투 엔드 테스트가 필수입니다.
- 컨트롤러는 반드시 뷰와 짝이 될 필요가 있습니다. 두 가지 구성 요소가 다른 컨트롤러와 뷰에서 가장 이용 가능하다라고 라우팅에 따라 컨트롤러를 정의하십시오.
- 참고 : 만약 뷰가 라우팅 이외의 다른 방법으로로드되어 있다면,
ng-controller = "Avengers as vm"
구문을 이용하십시오. - 이유 :
- 라우팅은 컨트롤러의 페어링을 수행하여 라우팅에 의해 다른 컨트롤러와 뷰 쌍을 호출 할 수 있습니다. 컨트롤러가
ng-controller
를 사용하여 뷰에 할당 된 경우에는 그 뷰는 항상 같은 컨트롤러에 할당됩니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
| /* avoid - when using with a route and dynamic pairing is desired */ // route-config.js angular
.module('app')
.config(config);
function config($routeProvider) {
$routeProvider
.when('/avengers', {
templateUrl: 'avengers.html'
});
}
| cs |
1
2
3
| <!-- avengers.html -->
<div ng-controller="Avengers as vm">
</div>
| cs |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| /* recommended */ // route-config.js angular
.module('app')
.config(config);
function config($routeProvider) {
$routeProvider
.when('/avengers', {
templateUrl: 'avengers.html',
controller: 'Avengers',
controllerAs: 'vm'
});
}
| cs |
1
2
3
| <!-- avengers.html -->
<div>
</div>
| cs |
- 서비스는
new
키워드로 인스턴스화됩니다. Public 메서드와 변수는this
를 사용하십시오. 이들은 팩토리도 마찬가지입니다 만, 일관성을 위해서는 서비스 대신 팩토리를 사용하십시오. - 참고 : 모든 Angular 서비스는 싱글 톤입니다 . 즉, 만들어진 서비스는 인젝터마다 단일 인스턴스 만 존재하지 않는다는 것을 의미합니다.
1 2 3 4 5 6 7 8 9 10 | // service angular .module('app') .service('logger', logger); function logger() { this.logError = function(msg) { /* */ }; } Colored by Color Scripter | cs |
1
2
3
4
5
6
7
8
9
10
11
12
| // factory angular
.module('app')
.factory('logger', logger);
function logger() {
return {
logError: function(msg) {
/* */
}
};
}
| cs |
- 팩토리는 단일 책임 이어야하며, 그 문맥에 따라 캡슐화됩니다. 팩토리가 하나의 목적을 초과하여 이용되기 시작하면 새로운 팩토리가 생성되어야합니다.
팩토리는 싱글 톤이며, 그 서비스의 멤버를 포함한 오브젝트를 돌려주세요.
Note : 모든 Angular 서비스는 싱글 톤입니다 .
호출 가능한 서비스의 구성원 (그 인터페이스)를 선두로 공개합니다. 이 기술은 Revealing Module Pattern 에 유래하고 있습니다.
왜? : 호출 가능한 멤버를 앞에 두는 것은 가독성이 뛰어나 어떤 서비스 멤버가 호출 가능한 단위 테스트된다 (and/ or mocked)이어야인지를 즉시 파악하는 데 도움이됩니다.
왜? :이게이 공개되어 있는지를보기 위해 스크롤해야수록 파일이 긴 경우에 특히 유용합니다.왜? : 세터 함수는 간단하지만 함수 선언을 한 줄 이상의 이루어진 경우에는 가독성이 떨어지는 스크롤이 필요합니다. 서비스에서 반환 값을 사용하여 호출 가능한 인터페이스를 정의하여 구현 세부 사항을 아래에 이동할 수 있습니다. 또한 인터페이스의 정의가 선두에 놓인다면 가독성을 높일 수 있습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| /* avoid */ function dataService() {
var someValue = '';
function save() {
/* */
};
function validate() {
/* */
};
return {
save: save,
someValue: someValue,
validate: validate
};
}
| cs |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| /* recommended */ function dataService() {
var someValue = '';
var service = {
save: save,
someValue: someValue,
validate: validate
};
return service;
////////////
function save() {
/* */
};
function validate() {
/* */
};
}
| cs |
구현의 상세를 숨기기 위해 함수 선언을 사용하십시오. 팩토리 액세스 가능한 멤버를 앞에두고주세요. 그 구성원은 해당 파일의 뒤에 나오는 함수 선언을 가리 키도록합니다. 자세한 내용은 이 포스트 를 참조하십시오.
왜? : 액세스 가능한 멤버를 선두로 작성하여 가독성이 올라 팩토리에서 어떤 함수가 외부에서 액세스 할 수 있는지 즉시 확인할 수 있습니다.
왜? : 구현의 상세를 파일의 후방에 배치하여 view에서 복잡성을 제거하고 중요한 것이 파일의 시작 부분에서 보이게됩니다.
왜? : 함수 선언이 철거되기 때문에 (함수 인 것 같은) 함수를 선언하기 전에 이용하고 버리는 우려가 없습니다.
왜? :
var b
앞에var a
를 이동하는 함수 선언이a
가b
에 의존해서 코드가 손상 버릴 염려 할 필요는 결코 없습니다.왜? : 함수는 순서가 중요합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
| /** * avoid * Using function expressions */ function dataservice($http, $location, $q, exception, logger) {
var isPrimed = false;
var primePromise;
var getAvengers = function() {
// implementation details go here
};
var getAvengerCount = function() {
// implementation details go here
};
var getAvengersCast = function() {
// implementation details go here
};
var prime = function() {
// implementation details go here
};
var ready = function(nextPromises) {
// implementation details go here
};
var service = {
getAvengersCast: getAvengersCast,
getAvengerCount: getAvengerCount,
getAvengers: getAvengers,
ready: ready
};
return service;
}
| cs |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
| /** * recommended * Using function declarations * and accessible members up top. */ function dataservice($http, $location, $q, exception, logger) {
var isPrimed = false;
var primePromise;
var service = {
getAvengersCast: getAvengersCast,
getAvengerCount: getAvengerCount,
getAvengers: getAvengers,
ready: ready
};
return service;
////////////
function getAvengers() {
// implementation details go here
}
function getAvengerCount() {
// implementation details go here
}
function getAvengersCast() {
// implementation details go here
}
function prime() {
// implementation details go here
}
function ready(nextPromises) {
// implementation details go here
}
}
| cs |
- 데이터 운영 및 팩토리와 데이터 상호 작용과 같은 로직을 리팩토링하십시오. XHR 호출 로컬 스토리지, 메모리에 대피 등의 데이터 작업을 담당하는 데이터 서비스를 생성하십시오.왜? : 컨트롤러의 책임은 프레젠테이션과 뷰를 위해 필요한 정보를 수집하는 것입니다. 어떻게 데이터를 검색하거나 신경 쓰지 않고 단순히 누구에게 문의해야할지 알고있을뿐입니다. 데이터 서비스 분할해서 어떻게 데이터를 검색하거나이라는 논리를 데이터 서비스로 이동하여 컨트롤러를 더 간단하게보기로 포커스시켜주십시오.왜? : 데이터 서비스를 이용하는 컨트롤러를 테스트 할 때 (mock or real) 데이터 호출을 쉽게 테스트 할 수 있습니다.왜? : 데이터 서비스의 구현은 데이터 저장소를 다루는 매우 특정 코드입니다. 이 코드는 헤더, 데이터 저장소의 사용 방법 또는
$ http
와 같은 다른 서비스를 포함한 것입니다. 그런 논리를 데이터 서비스로 나눠서 다른 consumers (아마도 컨트롤러)에서 구현 세부 정보를 숨기도록 한 장소에 캡슐화합니다. 이렇게하면 구현의 변경도 쉬워집니다
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
| /* recommended */ // dataservice factory angular
.module('app.core')
.factory('dataservice', dataservice);
dataservice.$inject = ['$http', 'logger'];
function dataservice($http, logger) {
return {
getAvengers: getAvengers
};
function getAvengers() {
return $http.get('/api/maa')
.then(getAvengersComplete)
.catch(getAvengersFailed);
function getAvengersComplete(response) {
return response.data.results;
}
function getAvengersFailed(error) {
logger.error('XHR Failed for getAvengers.' + error.data);
}
}
}
| cs |
- Note : 데이터 서비스 컨트롤러 같은 consumers에서 호출되지만 아래에 표시된대로 구현 consumers에서 숨겨집니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
| /* recommended */ // controller calling the dataservice factory angular
.module('app.avengers')
.controller('Avengers', Avengers);
Avengers.$inject = ['dataservice', 'logger'];
function Avengers(dataservice, logger) {
var vm = this;
vm.avengers = [];
activate();
function activate() {
return getAvengers().then(function() {
logger.info('Activated Avengers View');
});
}
function getAvengers() {
return dataservice.getAvengers()
.then(function(data) {
vm.avengers = data;
return vm.avengers;
});
}
}
| cs |
$ http
같은 promise를 반환하는 데이터 서비스를 호출 할 때 그것을 호출하는 함수도 마찬가지로 promise를 돌려주세요.왜? : promise를 함께 체인함으로써 데이터의 호출이 완료된 후 추가 조치를하고 그 promise를 resolve 또는 reject 할 수 있습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
| /* recommended */ activate();
function activate() {
/**
* Step 1 * Ask the getAvengers function for the * avenger data and wait for the promise */ return getAvengers().then(function() {
/**
* Step 4 * Perform an action on resolve of final promise */ logger.info('Activated Avengers View');
});
}
function getAvengers() {
/**
* Step 2 * Ask the data service for the data and wait * for the promise */ return dataservice.getAvengers()
.then(function(data) {
/**
* Step 3 * set the data and resolve the promise */ vm.avengers = data;
return vm.avengers;
});
}
| cs |
파일마다 한 지시어를 만들어주세요. 지시문 이름에서 파일 이름을 지정하십시오.
왜? : 모든 지시어를 하나의 파일에 넣는 것은 쉽지만 응용 프로그램간에 모듈 간 단 하나의 모듈과 공유하는 경우에도 빼내는 것은 어렵습니다.
왜? : 파일마다 하나의 지시문함으로써 유지 보수가 간편합니다.
Note : " Best Practice : 지시어는 자신이 클린업되어야합니다. 지시문이 제거 된 때 클린업 함수를 실행하기 위해element.on ( '$ destroy', ...)
와scope $ on ( '$ destroy', ...)
"를 이용해주세요 ... Angular 문서보다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
| /* avoid */ /* directives.js */ angular
.module('app.widgets')
/* order directive that is specific to the order module */
.directive('orderCalendarRange', orderCalendarRange)
/* sales directive that can be used anywhere across the sales app */
.directive('salesCustomerInfo', salesCustomerInfo)
/* spinner directive that can be used anywhere across apps */
.directive('sharedSpinner', sharedSpinner);
function orderCalendarRange() {
/* implementation details */
}
function salesCustomerInfo() {
/* implementation details */
}
function sharedSpinner() {
/* implementation details */
}
| cs |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| /* recommended */ /* calendarRange.directive.js */ /** * @desc order directive that is specific to the order module at a company named Acme * @example <div acme-order-calendar-range></div> */ angular
.module('sales.order')
.directive('acmeOrderCalendarRange', orderCalendarRange);
function orderCalendarRange() {
/* implementation details */
}
| cs |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| /* recommended */ /* customerInfo.directive.js */ /** * @desc sales directive that can be used anywhere across the sales app at a company named Acme * @example <div acme-sales-customer-info></div> */ angular
.module('sales.widgets')
.directive('acmeSalesCustomerInfo', salesCustomerInfo);
function salesCustomerInfo() {
/* implementation details */
}
| cs |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| /* recommended */ /* spinner.directive.js */ /** * @desc spinner directive that can be used anywhere across apps at a company named Acme * @example <div acme-shared-spinner></div> */ angular
.module('shared.widgets')
.directive('acmeSharedSpinner', sharedSpinner);
function sharedSpinner() {
/* implementation details */
}
| cs |
DOM을 직접 조작하는 경우에는 지시문을 사용하십시오. 만약 스타일을 설정하기 위해 CSS와 animation services , Angular 템플릿
ngShow
과ngHide
등 다른 방법이 있으면 대신 그것을 이용하는 것도 좋다. 예를 들어, 지시어가 단순히 표시와 비 표시를하는 것이라면, ngHide / ngShow를 사용해주세요.왜? : DOM 조작은 테스트 및 디버깅이 어렵 기 때문에 종종 좋은 방법 (예를 들어, CSS, 애니메이션, 템플릿)이 있습니다.
간결하고 독특한 내용을 잘 나타내는 지시문의 접두사를 붙여주세요. 예를 들어, HTML에서
acme-sales-customer-info
과 같이 선언되면acmeSalesCustomerInfo
과 같이됩니다.왜? : 독특하고 간결한 접두사는 지시어의 사용 장소와 유래를 확인합니다. 예를 들어,
cc-
접두어는 CodeCamper 응용 프로그램을 보여acme-
은 Acme company위한 지시문임을 나타냅니다.Note :
ng-
같은 Angular의 directives를 위해 예약되어있는 것은 피한다. 이름 충돌을 피하기 위해 Ionic Framework 의ion-
처럼 폭넓게 이용되고있는 지시어를 조사하십시오.
독립적으로 성립 요소와 같은 지시문을 만들 때 restrict 속성에
E
(사용자 지정 요소)를 지정하고 필요에 따라A
(사용자 정의 속성)을 지정하십시오. 일반적으로 독립적으로 컨트롤 할 수있는 것이면E
가 적합합니다. 일반적인 지침으로EA
는 허용되지만 독립형 때는 요소로 구현되는 것이 바람직하고, 기존의 DOM 조작 확장 위해서는 속성으로 구현되는 것이 바람직합니다.왜? : 의미가 있기 때문입니다.
왜? : 우리는 지시문을 클래스로 사용하는 것을 허락하고 있습니다 만, 만약 지시문이 요소로 일하고있는 것이면 요소가 더 의미가 있고, 또한 적어도 속성으로 이치에 맞는 것입니다.
Note : Angular 1.3 +를 EA가 기본입니다.
1
2
| <!-- avoid -->
<div class="my-calendar-range"></div>
| cs |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| /* avoid */ angular
.module('app.widgets')
.directive('myCalendarRange', myCalendarRange);
function myCalendarRange() {
var directive = {
link: link,
templateUrl: '/template/is/located/here.html',
restrict: 'C'
};
return directive;
function link(scope, element, attrs) {
/* */
}
}
| cs |
1
2
3
| <!-- recommended -->
<my-calendar-range></my-calendar-range>
<div my-calendar-range></div>
| cs |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| /* recommended */ angular
.module('app.widgets')
.directive('myCalendarRange', myCalendarRange);
function myCalendarRange() {
var directive = {
link: link,
templateUrl: '/template/is/located/here.html',
restrict: 'EA'
};
return directive;
function link(scope, element, attrs) {
/* */
}
}
| cs |
지시어가 일관성을 유지할 수 있도록 뷰와 컨트롤러의 페어링에서 사용되는
controller as
를 사용하십시오.왜? : 의미가 있고, 어렵지 않습니다.
Note : 아래의 지시문은 controllerAs를 이용하여 link와 지시어의 컨트롤러에서 scope를 사용하는 방법을 보여줍니다. 모두가 한자리에 맞게 템플릿을 인라인으로 넣고 있습니다.
Note : 의존성 주입 (dependency injection)에 관해서는 Manually Identify Dependencies 를 참조하십시오.
Note : 지시어의 컨트롤러가 지시문의 클로저 밖에 있다는 점에 유의하십시오. 이 작성하여 주입이return
후에 도달 할 수없는 코드를 생성 해 버리는 문제를 해결 할 수 있습니다.
1
| <div my-example max="77"></div>
| cs |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
| angular
.module('app')
.directive('myExample', myExample);
function myExample() {
var directive = {
restrict: 'EA',
templateUrl: 'app/feature/example.directive.html',
scope: {
max: '='
},
link: linkFunc,
controller: ExampleController,
controllerAs: 'vm',
bindToController: true // because the scope is isolated
};
return directive;
function linkFunc(scope, el, attr, ctrl) {
console.log('LINK: scope.min = %s *** should be undefined', scope.min);
console.log('LINK: scope.max = %s *** should be undefined', scope.max);
console.log('LINK: scope.vm.min = %s', scope.vm.min);
console.log('LINK: scope.vm.max = %s', scope.vm.max);
}
}
ExampleController.$inject = ['$scope'];
function ExampleController($scope) {
// Injecting $scope just for comparison
var vm = this;
vm.min = 3;
console.log('CTRL: $scope.vm.min = %s', $scope.vm.min);
console.log('CTRL: $scope.vm.max = %s', $scope.vm.max);
console.log('CTRL: vm.min = %s', vm.min);
console.log('CTRL: vm.max = %s', vm.max);
}
| cs |
1
2
3
4
| <!-- example.directive.html -->
<div>hello world</div>
<div>max={{vm.max}}<input ng-model="vm.max"/></div>
<div>min={{vm.min}}<input ng-model="vm.min"/></div>
| cs |
1
2
3
4
5
6
7
| // Alternative to above example function linkFunc(scope, el, attr, vm) {
console.log('LINK: scope.min = %s *** should be undefined', scope.min);
console.log('LINK: scope.max = %s *** should be undefined', scope.max);
console.log('LINK: vm.min = %s', vm.min);
console.log('LINK: vm.max = %s', vm.max);
}
| cs |
controller as
구문을 지시어로 사용 외부 scope를 지시문의 컨트롤러 scope에 바인딩하고 싶을 때는bindToController = true
를 사용하십시오.왜? : 외부의 scope를 지시문의 컨트롤러 scope에 바인딩하는 것이 용이합니다.
Note :bindToController
는 Angular 1.3.0에서 도입되었습니다.
1
| <div my-example max="77"></div>
| cs |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
| angular
.module('app')
.directive('myExample', myExample);
function myExample() {
var directive = {
restrict: 'EA',
templateUrl: 'app/feature/example.directive.html',
scope: {
max: '='
},
controller: ExampleController,
controllerAs: 'vm',
bindToController: true
};
return directive;
}
function ExampleController() {
var vm = this;
vm.min = 3;
console.log('CTRL: vm.min = %s', vm.min);
console.log('CTRL: vm.max = %s', vm.max);
}
| cs |
1
2
3
4
| <!-- example.directive.html -->
<div>hello world</div>
<div>max={{vm.max}}<input ng-model="vm.max"/></div>
<div>min={{vm.min}}<input ng-model="vm.min"/></div>
| cs |
activate
함수에서 컨트롤러를 시작할 논리를 해결하십시오.왜? : 시작 로직 컨트롤러 중 불일치하는 곳으로 배치하여 테스트의 위치를 확인하고 더 일관성 잡힌 테스트를 실시하는 것을 용이하게합니다. 또한 컨트롤러 전체에 활성화 논리가 분산되어 버리는 것을 방지하는 데 도움이됩니다.
왜? : 컨트롤러의
activate
컨트롤러 / 뷰 새로 고침하는 로직을 재사용하는 데 유용합니다. 또한 로직을 함께 결합하여 사용자가보기에 빨리 도착할 수 있습니다.ng-view
이나ui-view
에 애니메이션을 넣는 것도 쉽게되므로, 사용자는 발랄한 동작이라고 느낍니다.Note : 만약 컨트롤러를 사용하기 전에 조건으로 라우팅을 취소해야한다면 대신 route resolve 를 사용하십시오.
1
2
3
4
5
6
7
8
9
10
11
| /* avoid */ function Avengers(dataservice) {
var vm = this;
vm.avengers = [];
vm.title = 'Avengers';
dataservice.getAvengers().then(function(data) {
vm.avengers = data;
return vm.avengers;
});
}
| cs |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| /* recommended */ function Avengers(dataservice) {
var vm = this;
vm.avengers = [];
vm.title = 'Avengers';
activate();
////////////
function activate() {
return dataservice.getAvengers().then(function(data) {
vm.avengers = data;
return vm.avengers;
});
}
}
| cs |
컨트롤러가 활성 베이트되기 전에 promise가 해결되는 것에 의존하는 경우 컨트롤러의 로직이 실행되기 전에
$ routeProvider
에서 그 의존이 해결됩니다. 만약 컨트롤러가 활성 베이트되기 전에 조건으로 라우팅을 취소하려면 route resolve를 사용하십시오.뷰 전환하기 전에 라우팅 취소를 판단하고자 할 때에는 route resolve를 사용하십시오.
왜? : 컨트롤러가로드되기 전에 데이터가 필요할지도 모릅니다. 그 데이터는 사용자의 팩토리와 $ http 에서 반환 promise에서 얻을 수 없습니다. route resolve 를 사용하면 컨트롤러 로직을 실행하기 전에 promise를 해결할 수 있기 때문에 promise에서 얻은 데이터를 바탕으로 조치를 취할 수 있습니다.
왜? 라우팅 및 컨트롤러 activate 함수 뒤에 코드가 실행되어보기가 즉시로드됩니다. 액티 베이트 된 promise가 resolve되면 데이터 바인딩이 시작된다. 보기를 전환하는 동안 (
ng-view
이나ui-view
에서) "busy"애니메이션이 표시됩니다.Note : promise 후 라우팅이 완료되기 전에 코드가 실행됩니다. 만약 그 promise가 reject되면 라우팅은 취소됩니다. resolve 의해 새로운 뷰는 라우팅이 해결 될 때까지 기다립니다. resolve 및 뷰 전환이 끝날 때까지 "busy"애니메이션이 표시됩니다. 더 빨리보기를 표시 할 경우, 또한 뷰를 표시할지 여부 체크 포인트가 불필요한 경우에는 대신 controlleractivate
Technique 을하는 것을 고려하십시오.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| /* avoid */ angular
.module('app')
.controller('Avengers', Avengers);
function Avengers(movieService) {
var vm = this;
// unresolved
vm.movies;
// resolved asynchronously
movieService.getMovies().then(function(response) {
vm.movies = response.movies;
});
}
| cs |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
| /* better */ // route-config.js angular
.module('app')
.config(config);
function config($routeProvider) {
$routeProvider
.when('/avengers', {
templateUrl: 'avengers.html',
controller: 'Avengers',
controllerAs: 'vm',
resolve: {
moviesPrepService: function(movieService) {
return movieService.getMovies();
}
}
});
}
// avengers.js angular
.module('app')
.controller('Avengers', Avengers);
Avengers.$inject = ['moviesPrepService'];
function Avengers(moviesPrepService) {
var vm = this;
vm.movies = moviesPrepService.movies;
}
| cs |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
| /* even better */ // route-config.js angular
.module('app')
.config(config);
function config($routeProvider) {
$routeProvider
.when('/avengers', {
templateUrl: 'avengers.html',
controller: 'Avengers',
controllerAs: 'vm',
resolve: {
moviesPrepService: moviesPrepService
}
});
}
function moviesPrepService(movieService) {
return movieService.getMovies();
}
// avengers.js angular
.module('app')
.controller('Avengers', Avengers);
Avengers.$inject = ['moviesPrepService'];
function Avengers(moviesPrepService) {
var vm = this;
vm.movies = moviesPrepService.movies;
}
| cs |
movieService
에 대한 의존도는 minification로부터 안전하지 않습니다. 어떻게 코드를 minification 안전하거나 자세한 내용은 dependency injection 과 minification and annotation 을 참조하십시오.minification 안전한 접근을 이용하지 않고 바로 가기 의존을 선언하는 구문은 피해주십시오.
왜? : 구성 요소 (즉, 컨트롤러 및 공장 등)에 대한 파라미터는 망글 된 변수로 변환됩니다. 예를 들어,common
과dataservice
는a
또는b
가 될 수도 있고, Angular를 찾지 않을지도 모릅니다.
1
2
3
4
5
6
7
| /* avoid - not minification-safe*/ angular
.module('app')
.controller('Dashboard', Dashboard);
function Dashboard(common, dataservice) {
}
| cs |
1
2
| /* avoid - not minification-safe*/ angular.module('app').controller('Dashboard', d);function d(a, b) { }
| cs |
Angular 컴포넌트의 의존성을 수동으로 식별하기 위해
$ inject
를 사용하십시오.왜? :이 기술은
ng-annotate
으로 이용되고 있으며, 그것은 자동으로 minification 안전 의존을 생성하는 것을 권장합니다. 만약ng-annotate
가 주입이 이미 완료되었음을 감지하면 다시 생성을 건너 뜁니다.왜? :이 기술은 매개 변수가 망글 된 때 minification 문제에 취약이기 때문에 의존성을 보호합니다. 예를 들어,
common
과dataservice
가a
와b
가 될 수도 있고, Angular를 찾지 않을지도 모릅니다.왜? : 배열에서보기 힘든 항해와 긴 목록이 될 경우 인라인 의존성을 생성하는 것을 피해주십시오. 또한 종속 목록은 배열이 문자열의 연속으로 이루어진 반면, 마지막 요소가 구성 요소의 기능이 혼란입니다.
1
2
3
4
5
6
7
| /* avoid */ angular
.module('app')
.controller('Dashboard',
['$location', '$routeParams', 'common', 'dataservice',
function Dashboard($location, $routeParams, common, dataservice) {}
]);
| cs |
1
2
3
4
5
6
7
8
| /* avoid */ angular
.module('app')
.controller('Dashboard',
['$location', '$routeParams', 'common', 'dataservice', Dashboard]);
function Dashboard($location, $routeParams, common, dataservice) {
}
| cs |
1
2
3
4
5
6
7
8
9
| /* recommended */ angular
.module('app')
.controller('Dashboard', Dashboard);
Dashboard.$inject = ['$location', '$routeParams', 'common', 'dataservice'];
function Dashboard($location, $routeParams, common, dataservice) {
}
| cs |
$ inject
가 도달 가능하게 될지도 모릅니다 (지시어 일어날지도 모릅니다). 이것은 컨트롤러를 지시문의 바깥쪽으로 이동하여 해결할 수 있습니다.1
2
3
4
5
6
7
8
9
10
11
12
13
| /* avoid */ // inside a directive definition function outer() {
var ddo = {
controller: DashboardPanelController,
controllerAs: 'vm'
};
return ddo;
DashboardPanelController.$inject = ['logger']; // Unreachable
function DashboardPanelController(logger) {
}
}
| cs |
1
2
3
4
5
6
7
8
9
10
11
12
13
| /* recommended */ // outside a directive definition function outer() {
var ddo = {
controller: DashboardPanelController,
controllerAs: 'vm'
};
return ddo;
}
DashboardPanelController.$inject = ['logger'];
function DashboardPanelController(logger) {
}
| cs |
Angular 구성 요소의 route resolver의 의존성을 수동으로 식별하기 위해
$ inject
를 사용하십시오.왜? :이 기술은 route resolver를 익명 함수로 밖에내는 것으로 가독성을 높일 수 있습니다.
왜? :$ inject
문장을 단지 앞에 위치하여 resolver가 어떠한 의존성도 minification 안전합니다.1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17/* recommended */function config($routeProvider) {$routeProvider.when('/avengers', {templateUrl: 'avengers.html',controller: 'AvengersController',controllerAs: 'vm',resolve: {moviesPrepService: moviesPrepService}});}moviesPrepService.$inject = ['movieService'];function moviesPrepService(movieService) {return movieService.getMovies();}Colored by Color Scriptercs
Gulp 와 Grunt 위해 ng-annotate 를 사용해주세요. 자동 의존성 주입이 필요한 함수
/ ** @ngInject * /
라는 코멘트를 넣어주세요.왜? :이 것은 minification 안전 관행을 이용하지 않는 의존성에서 코드를 보호합니다.
왜? :
ng-min
은 비추천입니다.나는 읽고 쓰기 및 디버깅이 용이하기 때문에 Gulp 쪽을 선호합니다.
다음 코드는 minification 안전 의존성 주입을 사용하지 않습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| angular
.module('app')
.controller('Avengers', Avengers);
/* @ngInject */ function Avengers(storageService, avengerService) {
var vm = this;
vm.heroSearch = '';
vm.storeHero = storeHero;
function storeHero() {
var hero = avengerService.find(vm.heroSearch);
storageService.save(hero.name, hero);
}
}
| cs |
$ inject
가 부여 된 출력이 생성되고 그 출력은 minification 안전합니다.1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| angular
.module('app')
.controller('Avengers', Avengers);
/* @ngInject */ function Avengers(storageService, avengerService) {
var vm = this;
vm.heroSearch = '';
vm.storeHero = storeHero;
function storeHero() {
var hero = avengerService.find(vm.heroSearch);
storageService.save(hero.name, hero);
}
}
Avengers.$inject = ['storageService', 'avengerService'];
| cs |
ng-annotate
가 주입이 이미 이루어지고 있음을 감지하면 (예를 들어, @ngInject
가 감지되면), $ inject
가 들어간 코드를 중복 생성하지 않습니다./ * @ngInject * /
에 넣을 수 있습니다. 주입 된 의존성이 minification 안전이되도록 적절히 주석이 붙은 코드를 생성합니다.1
2
3
4
5
6
7
8
9
10
11
12
13
14
| // Using @ngInject annotations function config($routeProvider) {
$routeProvider
.when('/avengers', {
templateUrl: 'avengers.html',
controller: 'Avengers',
controllerAs: 'vm',
resolve: { /* @ngInject */
moviesPrepService: function(movieService) {
return movieService.getMovies();
}
}
});
}
| cs |
ngApp
지시문ngStrictDi
매개 변수를 사용할 수 있습니다. 현재 injector가 "strict-di"모드에서 생성 된 때 응용 프로그램이 명시 적으로 주석이 붙어 있지 않은 함수 (이들은 minification 안전하지는 않습니다) 호출이 실패합니다. 디버깅 정보를 로그로 console에 출력되므로 문제가있는 코드를 찾는 데 도움이됩니다. 나는 ng-strict-di
을 디버깅 용도로만 이용하는 것을 선호합니다. <body ng-app = "APP"ng-strict-di>
자동 빌드 작업 중 gulp-ng-annotate 또는 grunt-ng-annotate 를 사용해주세요. 의존성이있는 어떤 함수보다 먼저
/ * @ngInject * /
를 주입하십시오.왜? : ng-annotate는 대부분의 의존성을 포착되지만
/ * @ngInject * /
구문을 사용한 팁이 때때로 필요로 하 와리.다음 코드는 ngAnnotate를 사용한 gulp 작업의 예입니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| gulp.task('js', ['jshint'], function() {
var source = pkg.paths.js;
return gulp.src(source)
.pipe(sourcemaps.init())
.pipe(concat('all.min.js', {newLine: ';'}))
// Annotate before uglify so the code get's min'd properly.
.pipe(ngAnnotate({
// true helps add where @ngInject is not used. It infers.
// Doesn't work with resolve, so we must be explicit there
add: true
}))
.pipe(bytediff.start())
.pipe(uglify({mangle: true}))
.pipe(bytediff.stop())
.pipe(sourcemaps.write('./'))
.pipe(gulp.dest(pkg.paths.dev));
});
| cs |
예외가 발생했을 때
$ exceptionHandler
서비스를 재정 의하여 사용자 정의 작업을 수행하기 위해 config 호출시$ provide
서비스 decorator 를 사용하십시오.왜? : 개발시나 실행시에 포착되지 않은 Angular의 예외를 처리하는 일관된 방법을 제공합니다.
Note : 또 다른 옵션은 decorator를 사용하는 대신에 서비스를 재정의하는 것입니다. 또한 올바른 선택 사항이지만 만약 기본 동작을 유지하려는 경우 또는 확장하려면 decorator가 좋습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
| /* recommended */ angular
.module('blocks.exception')
.config(exceptionConfig);
exceptionConfig.$inject = ['$provide'];
function exceptionConfig($provide) {
$provide.decorator('$exceptionHandler', extendExceptionHandler);
}
extendExceptionHandler.$inject = ['$delegate', 'toastr'];
function extendExceptionHandler($delegate, toastr) {
return function(exception, cause) {
$delegate(exception, cause);
var errorData = {
exception: exception,
cause: cause
};
/**
* Could add the error to a service's collection, * add errors to $rootScope, log errors to remote web server, * or log locally. Or throw hard. It is entirely up to you. * throw exception; */ toastr.error(exception.msg, errorData);
};
}
| cs |
예외를 포착하고 세 심하게 처리하는 인터페이스를 제공하는 팩토리를 만들어주세요.
왜? : 코드가 던져진 수있는 예외 (예를 들어, XHR 호출이나 promise의 failures 등)를 포착하기위한 일관된 방법을 제공합니다.
Note : 예외 포수는 예외가 발생할지도 모른다 호출에 대해 특정 예외를 포착하고 그에 따라 처리를 할 때 유용합니다. 예를 들어, 원격 Web 서비스에서 데이터를 검색하는 XHR을 호출 할 때 해당 서비스에서 발생하는 어떠한 예외도 포착 고유하게 제공 할 때도 있습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| /* recommended */ angular
.module('blocks.exception')
.factory('exception', exception);
exception.$inject = ['logger'];
function exception(logger) {
var service = {
catcher: catcher
};
return service;
function catcher(message) {
return function(reason) {
logger.error(message, reason);
};
}
}
| cs |
$ routeChangeError
를 사용하여 모든 라우팅 오류를 처리하고 로그하십시오.왜? : 모든 라우팅 오류를 처리하는 일관된 방법을 제공합니다.
왜? : 만약 라우팅 오류가 발생했을 때 자세한 정보 또는 복구 옵션을 갖춘 사용자 친화적 인 화면에 라우팅 할 수 있으면 더 좋은 사용자 경험이 될 수 있습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
| /* recommended */ var handlingRouteChangeError = false;
function handleRoutingErrors() {
/**
* Route cancellation: * On routing error, go to the dashboard. * Provide an exit clause if it tries to do it twice. */ $rootScope.$on('$routeChangeError',
function(event, current, previous, rejection) {
if (handlingRouteChangeError) { return; }
handlingRouteChangeError = true;
var destination = (current && (current.title ||
current.name || current.loadedTemplateUrl)) ||
'unknown target';
var msg = 'Error routing to ' + destination + '. ' +
(rejection.msg || '');
/**
* Optionally log using a custom service or $log. * (Don't forget to inject custom service) */ logger.warning(msg, [current]);
/**
* On routing error, go to another route/state. */ $location.path('/');
}
);
}
| cs |
모든 구성 요소에 대해 특징과 선택적으로 그 형태를 나타내는 패턴에 따라 일관성있는 이름을 사용하십시오. 내 추천은
feature.type.js
입니다. 대부분의 자산에 대해 두 명명 부분이 있습니다.- 파일 이름 (
avengers.controller.js
) - Angular에 등록 할 구성 요소 이름 (
AvengersController
)
- 파일 이름 (
왜? : 명명 규칙은 첫눈에 내용이 있으면 같은 일관된 방법을 제공합니다. 일관성은 프로젝트 성공에 중요한 열쇠이고 팀에게 중요한 것입니다. 또한 회사 전체에서 아주 큰 효율성에 연결됩니다.
왜? : 명명 규칙은 코드를보다 빨리 발견하고 더 쉽게 이해하는 데 도움이됩니다.
모든 구성 요소에 대해 특징과 선택적으로 그 형태를 나타내는 패턴에 따라 일관성있는 이름을 사용하십시오. 내 추천은
feature.type.js
입니다.왜? : 빠르게 구성 요소를 식별 할 수있는 일관된 방법을 제공합니다.
왜? : 자동 태스크위한 패턴 매칭이 가능합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
| /** * common options */ // Controllers avengers.js
avengers.controller.js
avengersController.js
// Services/Factories logger.js
logger.service.js
loggerService.js
| cs |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
| /** * recommended */ // controllers avengers.controller.js
avengers.controller.spec.js
// services/factories logger.service.js
logger.service.spec.js
// constants constants.js
// module definition avengers.module.js
// routes avengers.routes.js
avengers.routes.spec.js
// configuration avengers.config.js
// directives avenger-profile.directive.js
avenger-profile.directive.spec.js
| cs |
avengers.controller.js
라는 파일 이름에서 controller
를 제거하고 명명하는 것입니다. 다른 모든 규칙은 접미사를 계속 사용할 것입니다. 컨트롤러는 가장 일반적인 구성 요소이며, 타이핑 양을 줄이면서 여전히 특정 가능한 상태로 유지됩니다. 어느 하나를 선택 팀내에서 하나의 명명 규칙을 통일하는 것을 추천합니다. 내 취향은 avengers.controller.js
입니다.1
2
3
4
5
6
| /** * recommended */ // Controllers
avengers.js
avengers.spec.js
| cs |
구성 요소뿐만 아니라 테스트 구성 요소에 접미사로
spec
을 부여한 형태로 테스트 스펙을 선정하십시오왜? : 구성 요소를 신속하게 식별하는 일관된 방법을 제공합니다.
왜? : karma 및 기타 테스트 러너에서 패턴 매칭이 가능합니다.
1
2
3
4
5
6
7
| /** * recommended */ avengers.controller.spec.js
logger.service.spec.js
avengers.routes.spec.js
avenger-profile.directive.spec.js
| cs |
모든 컨트롤러에 그 기능에서 따온 일관된 이름을 붙여주세요. 컨트롤러의 생성자는 어퍼 카멜 케이스를 사용하십시오.
왜? : 빠르게 콘토라을 확인하고 볼 수있는 일관된 방법을 제공합니다.
왜? : 어퍼 카멜 케이스는 생성자를 사용해 인스턴스를 생성 된 객체를 식별 약관적인 방법입니다.
1
2
3
4
5
6
7
8
9
10
| / **
* recommended
* /
// avengers.controller.js angular
.module
.controller ( ' HeroAvengersController ' , HeroAvengersController);
function HeroAvengersController () {}
| cs |
컨트롤러에
Controller
라는 이름을 삽입하십시오.왜? :Controller
접미사 널리 사용되고 분명히 직접 내용을 설명하고있다.
1
2
3
4
5
6
7
8
9
10
| / **
* recommended
* /
// avengers.controller.js angular
.module
.controller ( ' AvengersController ' , AvengersController);
function AvengersController () {}
| cs |
모든 팩터 리에서 기능에 따른 불일치하는 이름을 사용하십시오. 서비스 및 팩토리 이름은 카멜 케이스를 사용하십시오.
$
부터 시작 팩토리와 서비스 이름을 피해주십시오.왜? : 참조해야 팩토리를 재빨리 확인하는 데 일관성 잡힌 방법을 제공합니다.
왜? : 내장 된$
에서 시작 팩토리와 서비스 이름과 충돌을 피할 수 있습니다.
1
2
3
4
5
6
7
8
9
10
| / **
* recommended
* /
// logger.service.js angular
.module
.factory ( ' logger ' , logger);
function Logger () {}
| cs |
모든 디렉토리에 카멜 케이스로 일관성을 가지고 이름을 사용하십시오. 지시어가 속하는 범위를 나타내는 짧은 접두사 (예를 들면 회사 나 프로젝트의 접두사)를 사용하십시오.
왜? : 참조 할 컴퍼넌트와 재빨리 확인하는 데 일관성 잡힌 방법을 제공합니다.
1
2
3
4
5
6
7
8
9
10
11
12
| / **
* recommended
* /
// avenger-profile.directive.js angular
.module
.directive ( ' xxAvengerProfile ' , xxAvengerProfile);
// usage is <xx-avenger-profile> </ xx-avenger-profile> function xxAvengerProfile () {}
| cs |
여러 모듈이있을 때, 메인이되는 모듈의 파일은
app.module.js
라고 명명하고 다른 사람에 의존하는 모듈은 그것이 나타내는 내용에 따라 명명하십시오. 예를 들어, admin 모듈은admin.module.js
라고 명명합니다. register되는 모듈 이름은 각각app
과admin
입니다.왜? : 여러 개의 모듈로 구성된 응용 프로그램 또는 대규모 응용 프로그램에 확장 될 때 일관성을줍니다.
왜? : 자동 태스크를 사용하여 정의 된 모든 모듈을 처음로드 한 다음 다른 Angular 파일을 (bundling을위한)로드하는 간단한 방법을 제공합니다.
모듈의 구성을 각각의 모듈에 따라 명명 된 파일에 분리하십시오. 메인
app
모듈의 구성은app.config.js
라고 명명하십시오. (혹은 단순히config.js
). 모듈의 이름이admin.module.js
이면 그 구성은admin.config.js
라고 명명합니다.왜? : 모듈의 정의와 구성 요소 활성 코드에서 구성을 분리 할 수 있습니다.
왜? : 모듈의 구성을 설정하기 위해 위치를 파악할 수 있습니다.
- 라우팅 구성을 각각의 파일로 분리하십시오. 예를 들어, 기본 모듈이
app.route.js
이면admin
모듈은admin.route.js
됩니다.예 작은 응용 프로그램도, 다른 구성에서 라우팅을 분리하는 것을 선호합니다.
코드를 빠르게
L
ocate (배치)하기 때문에 첫눈에 그 코드를I
dentify (식별) 때문에 가능한F
lattest로 유지되도록 DRY되도록 (
T`ry) 응용 프로그램을 구조화 하십시오. 응용 프로그램의 구조는 이러한 4 가지 지침을 따라야합니다.왜 LIFT? : 일관성 잡힌 구조에 의해 충분히 규모 모듈화 된 코드의 위치를 신속하게 식별 할 수 있도록 개발의 효율성도 높아집니다.응용 프로그램의 구조를 확인하는 또 다른 방법은 다음을 자신에게 물어 보는 것입니다 :있는 기능에 대해 얼마나 신속하게 모든 관련 파일을 열고 그리고 변경할 수 있을까요?
만약 자신의 구조가 좋다고 생각하지 않으면, 되돌아 이러한 LIFT 지침을 검토하십시오.
- 코드를 쉽게
L
ocating 수 - 첫눈 코드를
I
dentify 수 - 가능한 코드를
F
LAT 구조 할 - DRY (Do not Repeat Yourself) 상태가되도록 (
T
RY) or T-DRY
- 코드를 쉽게
코드의 위치를 직관적으로 간단하고 빠르게 할 수 있도록하십시오.
Why? :이 프로젝트에 매우 중요한 것입니다. 만약 팀이 그들이 변화해야 파일을 빠르게 찾을 수 없으면 최대한 효율적으로 일할 수 없게되어 버립니다. 그런 때 구조를 변경해야합니다. 파일 이름을 모르는, 혹은 관련 파일을 모르는 것 같으면 파일을 가장 직관적이고 서로 가까운 위치에 둘 수 있다면 상당한 시간 절감됩니다. 이해하기 쉬운 폴더 구성 그런 몇시에 도움이됩니다.
/ bower_components
/ client
/ app
/ avengers
/ blocks
/ exception
/ logger
/ core
/ dashboard
/ data
/ layout
/ widgets
/ content
index.html
.bower.json
파일을 참조 할 때 해당 파일이 무엇을 포함 무엇을하려고하는지 즉시 이해할 수 있어야합니다.
왜? : 코드를 찾고 내용을 요약 해 보는 데 걸리는 시간이 줄어들 것으로보다 효율적입니다. 이것은 더 긴 파일 이름을 요구하고 있다면, 그렇게해야한다는 것입니다. 내용을 잘 나타내는 파일 이름을 지정하고 파일의 내용은 단 하나의 구성 요소 만합니다. 여러 컨트롤러 나 서비스, 또는 그들이 하나의 파일에 혼합하는 것을 피해주십시오. 그렇지 않으면,이 파일마다 하나의 구성 요소라는 규칙을 일탈 해 버립니다. 규칙을 지킴으로써 모두가 서로 관계하고있는 것 같은 아주 작은 기능의 모임이 있었다 때도 여전히 파일을 쉽게 식별 할 수 있습니다.
가능한 폴더 구성을 평평하게 유지하십시오. 7 개 이상의 파일이있는 경우는 분할을 검토하기 시작하십시오.
왜? : 파일을 찾을 수 7 계층 이상의 파일을 찾고 싶은 사람은 없습니다. Web 사이트의 메뉴에 대해 생각하면, 2 개 이상의 깊은 계층은 재고의 여지가 있습니다. 하나의 폴더 구성에서는 엄격한 수의 규칙은 아니지만, 폴더가 7-10 파일로 구성된 경우 하위 폴더를 만들 때지도 모릅니다. 자신이 편안 수준에 따라 결정하면 좋다. 새 폴더를 만들 명백한 (나머지 LIFT에 도움위한) 수준까지는 평면 구조를 사용해주세요.
DRY 해주세요. 하지만 그것에 사로 잡혀 너무 가독성을 희생해서는 안됩니다.
왜? : DRY 인 것은 중요하지만 결정적으로 중요한 것은 없습니다. 만약 LIFT 안쪽에 무언가 하나를 희생한다면 그것을 나는 T-DRY라고 부르고 있습니다. 하나의 뷰를 session-view.html를 입력하고 싶지는 않습니다. 왜냐하면 그것은 분명보기 때문입니다. 분명히 아닌 경우 또는 규칙에 의한 경우 그렇게 명명합니다.
구현에 대한 단기적 관점과 장기적 비전을 가지고 바랍니다. 즉, 작게 시작하지만 앱이 어떤 방향으로 가고 있는지를 확실히 파악하는 것입니다. 모든 응용 프로그램 코드는
app
라는 루트 디렉토리 아래에 보관하세요. 어떤 콘텐츠도 파일마다 한 기능하십시오. 컨트롤러 서비스 모듈 뷰의 각각을 별도의 파일로하십시오. 모든 타사 공급 업체의 스크립트는 다른 루트 디렉토리 아래에두고app
디렉토리 아래에 두지 마십시오. 나는 그 스크립트를 작성하지 않습니다 그리고 그것이 자신의 응용 프로그램을 어수선하게 버리는 것도 원하지 않습니다 (bower_components
,scripts
,lib
).Note :이 구조의 세부 사항 및 이유 등 this original post on application structure 를 참조하십시오.
응용 프로그램의 전체 레이아웃을 정의하는 구성 요소는
layout
이라는 폴더에 넣습니다. 이 디렉토리에는 뷰 템플릿과 탐색, 메뉴, 콘텐츠 영역 및 기타 장소에서의 컨테이너처럼 작동 컨트롤러를 포함 할지도 모릅니다.왜? : 모든 레이아웃을 한 곳에 배치하여 애플리케이션에서 재사용 할 수 있습니다.
특징을 나타내는 이름으로 폴더를 작성하십시오. 폴더가 7 개 이상의 파일을 포함하도록 부풀어 왔을 때 그들을 위해 폴더를 만드는 것을 고려하십시오. 사람에 따라 임계 값은 다를지도 모르기 때문에 필요에 따라 조정하십시오.
왜? : 개발자가 코드를 배치하고 첫눈에 각각의 파일이 무엇을하고 있는지 이해할 수 있습니다. 또한 가능한 한 평면 구조를 유지하기위한 중복도 낭비없는 이름 일 수 있습니다.
왜? : LIFT 지침이 모두 커버됩니다.
왜? : 콘텐츠 구성 LIFT의 지침에 따라 계속 유지할 것으로 앱이 어질러 져 버리는 것을 방지 할 수 있습니다.
왜? : 대량의 파일 (10 개 이상)이있을 때이를 일관성 잡힌 폴더에 배치하는 것은 간단하지만, 단일 구조로 배치하는 것은 어려울 것입니다.
/ ** * recommended * / app / app.module.js app.config.js components / calendar.directive.js calendar.directive.html user - profile.directive.js user - profile.directive.html layout / shell.html shell.controller.js topnav.html topnav.controller.js people / attendees.html attendees.controller.js people.routes.js speakers.html speakers.controller.js speaker - detail.html speaker - detail.controller.js services / data.service.js localstorage.service.js logger.service.js spinner.service.js sessions / sessions.html sessions.controller.js sessions.routes.js session - detail.html session - detail.controller.js
/ * * avoid * Alternative folders-by-type. * I recommend "folders-by-feature"instead. * / app / app.module.js app.config.js app.routes.js directives.js controllers / attendees.js session - detail.js sessions.js shell.js speakers.js speaker - detail.js topnav.js directives / calendar.directive.js calendar.directive.html user - profile.directive.js user - profile.directive.html services / dataservice.js localstorage.js logger.js spinner.js views / attendees.html session - detail.html sessions.html shell.html speakers.html speaker - detail.html topnav.html
하나의 책임을 캡슐화 한 작은 모듈을 만들어주세요.
왜? : 모듈화 된 응용 프로그램은 개발팀이 응용 프로그램의 수직 슬라이스를 쉽게 조립 증분 롤아웃 할 수 있습니다. 즉 개발 한 새로운 기능을 플러그인 할 수 있습니다.
- 모든 모듈과 기능을 통합하는 것을 담당하는 응용 프로그램의 루트되는 모듈을 만들어주세요. 이 응용 프로그램 이름을 클릭하세요.왜? : Angular는 모듈화 및 분할 패턴을 권장하고 있습니다. 다른 모듈을 연결하는 응용 프로그램의 루트 모듈을 만드는 것은 모듈을 추가하거나 삭제하는 간단한 방법을 제공합니다.
응용 프로그램 모듈에서 로직 통합 부분에만 보관하세요. 각각의 모듈 중의 기능은 그대로하십시오.
왜? : 응용 프로그램의 루트에 원격 데이터 수집 뷰의 표시 또는 응용 프로그램에 통합과 관계없는 다른 로직 등의 역할을 추가하는 것은 응용 프로그램을 더 혼란시키고 기능 세트를 재사용 또는 해제 하는 것을 더 어렵게합니다.
왜? : 루트 모듈은 어떤 모듈이 응용 프로그램을 구성하는 방법을 설명하는 매니페스트됩니다.
재사용이 가능한 공유되는 기능 영역에서 모듈을 작성하십시오. 레이아웃처럼, 서비스 및 대시 보드 애플리케이션 스페시 픽 기능 (예를 들어, 고객, 직업 : 관리 영업)이 거기에 해당합니다.
왜? : 독립적 인 모듈은 충돌이 거의 없거나 전혀없는 형태로 응용 프로그램에 추가 할 수 있습니다.
왜? : 스프린트 나 반복 중에 기능 영역에 집중하고 전력 질주와 반복의 끝은 그 기능을 켤 수 있습니다.
왜? : 기능 영역에서 모듈로 분할하여 코드의 분리 및 재사용이 가능하며, 모듈 테스트가 용이합니다.
재사용 가능한 응용 프로그램 블록 모듈을 작성하십시오. 예외 핸들링, 로그 다이아 보안 로컬 데이터의 대피와 같은 일반적인 서비스가 이에 해당합니다.
왜? :이 기능은 많은 응용 프로그램에서 필요 각각 모듈로 분리하는 것을 계속해서 제네릭가 응용 프로그램에서 재사용 가능합니다.
루트 모듈은 응용 프로그램 스페시 픽 모듈과 공유 또는 재사용되는 모듈에 따라 달라집니다.
왜? : 기본 응용 프로그램 모듈은 응용 프로그램의 기능을 빠르게 식별 가능한 매니페스트를 포함합니다.
왜? : 각 기능 영역은 그것이 얼마나 의존하고 있는지를 보여 주었다 매니페스트를 포함하고 있습니다. 그 덕분에 기능 영역은 의존성을 얻을 수 있으며, 예를 다른 응용 프로그램 중 이어도 작동합니다.
왜? : 데이터를 공유하는 서비스와 같은 응용 프로그램의 기능은
app.core
(이 모듈은 좋아하는 이름을 선택하십시오)과 같이 요약하여 쉽게 위치를 식별하거나 공유 할 수 입니다.Note : 이것은 일관성을위한 전략입니다. 여기에는 많은 좋은 옵션이 있습니다. Angular 의존 규칙에 따라 일관성을 잡기 위하여 그 하나를 선택하여 유지 보수하고 확장시키는 것이 용이합니다.
내 구조는 프로젝트간에 약간 바뀌어 있습니다 만, 구조 및 모듈화에 관해서는이 지침에 따라 있습니다. 구현은 기능이나 팀에 의존하고 변화 할지도 모릅니다. 즉, 동일한 구조를 고집하고있는 것이 아니라 일관성과 유지 보수 효율성을 염두에두고 옳은 일을하는 것입니다.
작은 응용 프로그램에서 공유되는 모든 종속을 기능적인 모듈과 직접적인 의존이없는 모듈 속에 넣어 버리는 것도 검토하십시오.이 방법은 작은 응용 프로그램 유지 보수 작업을 용이하게되지만 응용 프로그램 외부에서 모듈을 재사용하는 것은 어렵습니다.
angular 앱이 달리기 전에 구성이 설정되는 module configuration 코드를 주입하십시오. provider와 constants가 포함되는 것이 이상적입니다.
왜? : 설정을하는 부분이 더 적습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| angular
.module ( ' app ' )
.config (configure);
configure $ inject =
[ ' routerHelperProvider ' , ' exceptionHandlerProvider ' , ' toastr ' ];
function configure ( routerHelperProvider , exceptionHandlerProvider , toastr ) {
exceptionHandlerProvider.configure (config.appErrorPrefix);
configureStateHelper ();
toastr. options .timeOut = 4000 ;
toastr. options .positionClass = ' toast-bottom-right ' ;
////////////////
function configureStateHelper () {
routerHelperProvider.configure ({
docTitle : ' NG-Modular : '
});
}
}
| cs |
응용 프로그램이 시작될 때 실행되는 어떤 코드도 팩토리로 선언 된 함수를 통해 공개되며 run block 으로 주입되어야합니다.
왜? : 코드를 run 블록에 직접 넣어 버리면 테스트하는 것이 어렵습니다. 팩토리 두는 것으로 추상화 모의 화하는 것이 용이합니다.
1
2
3
4
5
6
7
8
9
10
| angular
.module ( ' app ' )
.run (runBlock);
runBlock $ inject = [ ' authenticator ' , ' translator ' ];
function runBlock ( authenticator , translator ) {
authenticator.initialize ();
translator.initialize ();
}
| cs |
document
및window
대신$ document
와$ window
를 사용하십시오.왜? :이 서비스는 Angular 의해 싸여 있기 때문에 직접 document 나 window를 사용하는 것보다는 테스타부루됩니다. 이를 통해 자신 document 나 window를 모의하는 것을 피할 수 있습니다.
setTimeout
과setInterval
대신$ timeout
과$ interval
을 사용하십시오.왜? :이 서비스는 Angular 의해 싸여 있기 때문에 더 테스타부루됩니다. 또한 Angular의 digest 사이클에서 처리되므로 데이터 바인딩이 동기화 계속됩니다.
단위 테스트는 깨끗한 코드를 유지하는 데 도움이됩니다. 더 자세한 정보는 내 추천하는 몇 가지 단위 테스트의 기초를 링크와 함께 소개하고 있습니다.
모든 스토리의 테스트를 써주세요. 빈 테스트부터 시작 스토리마다 코드를 작성 내용을 채워주세요.
왜? : 테스트 데스크 기술서를 작성하는 것은 스토리가 무엇을하고 무엇을하는지, 무엇을 가지고 성공으로 간주인지를 명확하게 정의하는 데 도움이됩니다.
it ( ' should have Avengers controller ' , function () { // TODO }); it ( ' should find 1 Avenger when filtered by name ' , function () { // TODO }); it ( ' should have 10 Avengers ' , function () { // TODO (mock data?) }); it ( ' should return Avengers via XHR ' , function () { // TODO ($ httpBackend?) }); // and so on
테스트 주자로는 Karma 를 사용해주세요.
왜? : Karma 한 번만 실행하거나 코드가 변경되었을 때 자동으로 실행하는 방법을 간단하게 설정할 수 있습니다.
왜? : Karma는 자기 부담의 테스트 러너 혹은 Grunt 나 Gulp을 이용한 지속적인 통합 프로세스에 쉽게 연결할 수 있습니다.
왜? : WebStorm 및 Visual Studio 등의 일부 IDE는 Karma를 통합하기 시작하고 있습니다.
왜? : Karma는 Grunt (와 grunt-karma ) and Gulp (과 gulp-karma ) 등 자동화 작업에서 제대로 작동합니다.
스텁 및 스파이 위해 Sinon 를 사용해주세요.
왜? : Sinon은 Jasmin과 Mocha와 함께 제대로 작동하지 스텁 및 스파이의 기능을 확장합니다.
왜? : 만약 Jasmine와 Mocha 모두를 시도 싶다면 Sinon은 그들을 쉽게 전환 할 수 있습니다.
왜? : 테스트 주장에 실패했을 때 Sinon은 서술 적 메시지입니다.
서버에서 테스트를 실행할 때 PhantomJS 를 사용해주세요.
왜? : PhantomJS는 헤드리스 브라우저이며, "visual"브라우저를 필요로하지 않고 테스트를 수행하는 데 도움이됩니다. Chrome과 Safari, IE와 다른 브라우저를 서버에 설치할 필요가 없습니다.
Note : 그럼에도 불구하고, 대상 사용자의 환경에서 모든 브라우저에서 테스트를해야합니다.
테스트에서 JSHint을 실행하십시오.
왜? : 테스트도 코드입니다. JSHint 테스트가 제대로 작동하지 않을지도 모른다 코드의 품질 문제를 파악하는 데 도움이됩니다.
테스트 코드는
describe
와expect
같은 일반적인 글로벌 변수를 용서하도록 규칙을 풉니 다.왜? : 테스트도 코드이며, 프로덕션의 코드와 마찬가지로주의를 기울 코드 품질의 규칙이 필요합니다. 그러나 테스트 프레임 워크에서 사용되는 전역 변수는 예를 들어, 테스트의 스펙에 다음을 포함하여 이완합니다. Mocha 가고있는 것처럼 표현에도 규칙을 풉니 다.
/ * jshint -W117, -W030 * /
Or you can add the following to your JSHint Options file.
" jasmine " : true , " mocha " : true ,
단위 테스트 파일 (스펙)은 클라이언트 코드와 병렬로 보관하세요. 서버 통합 및 여러 구성 요소 테스트를 커버하는 스펙은
tests
폴더에 보관하세요.왜? : 단위 테스트는 특정 구성 요소와 소스 파일에 직접 상관이 있습니다.
왜? : 항상 보이는 곳에 그들을두고 최신 상태로 유지하는 것이 더 쉽습니다. TDD 또는 개발 중에 테스트하거나 개발 후 테스트에 상관없이 코딩을 할 때 스펙이 옆에 줄에 보이지 않을 수도 신경이 쓰이지 않을 수 없도록하십시오. 이렇게하면 더 유지 관리되도록되어, 코드 커버리지도 올라갈 것입니다.
왜? : 소스 코드를 업데이트 할 때 동시에 테스트도 업데이트하는 것이 쉽습니다.
왜? : 일률적으로 두는 것은 찾아내는 것을 쉽게 소스를 이동할 때 맞추어 움직일 수 있습니다.
왜? : 가까이 스펙 파일을 두는 것은 소스 코드 지도자가 그 구성 요소가 어떻게 사용되는지를 배울 수 및 알려진 제한이 쉽게 알아낼 수 용이 해집니다.
왜? : grunt와 gulp 절대로 배포 용 빌드에 포함되지 않도록 스펙을 분할하는 것은 간단합니다.
/src/client/app/customers/customer-detail.controller.js
/customer-detail.controller.spec.js
/customers.controller.js
/customers.controller.spec.js
/customers.module.js
/customers.route.js
/customers.route.spec.js
뷰 및 주요 뷰지아루 요소에서 상태 간을 전환하기 위해 현명한 animations with Angular 를 사용하십시오. ngAnimate module을 포함해야합니다. 세 키 태연, 부드러움, 그리고 원활한입니다.
왜? : 현명한 애니메이션은 적절하게 사용 됨으로써 사용자 경험을 개선합니다.
왜? : 현명한 애니메이션은 뷰 전환시에 느끼는 성능을 개선합니다.
듀레이션이 짧은 애니메이션을 사용하십시오. 나는 대략 300 밀리 초에서 처음으로 적절한 곳까지 조정합니다.
왜? : 긴 애니메이션은 응용 프로그램이 느린 느낌을주고 사용자 경험과 체감 성능에 역효과가됩니다,
전통적인 애니메이션은 animate.css 를 사용해주세요.
왜? : animation.css가 제공하는 애니메이션은 빠르고, 부드럽고, 응용 프로그램에 쉽게 추가 할 수 있습니다.
왜? : 애니메이션에 일관성을 갖게합니다.
왜? : animate.css 널리 이용되고 테스트되어 있습니다.
Note :이 Matias Niemelä에 따르면 Angular 애니메이션의 멋진 포스트 를보십시오.
만약 문서 작성을 계획하고 있다면, 함수 이름, 설명, 인수 및 반환 값을 설명하는 데
jsDoc
구문을 사용하십시오. 응용 프로그램의 구조에 맞게@namespace
과@memberOf
를 사용해주세요.왜? : 풀 스크래치로 문서를 작성하는 대신, 코드에서 문서를 생성 (다시 생성) 할 수 있습니다.
왜? : 일반적인 생산성 도구를 사용하여 일관성을 유지할 수 있습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
| / **
* Logger Factory
* @namespace Factories
* /
( function () {
angular
.module ( ' app ' )
.factory ( ' logger ' , logger);
/ **
* @namespace Logger
* @desc Application Wide Logger
* @memberOf Factories
* /
function Logger ( $ log ) {
var 서비스 = {
logError : logError
};
return 서비스;
////////////
/ **
* @name logError
* @desc Logs errors
* @param {String} msg Message to log
* @returns {String}
* @memberOf Factories.Logger
* /
function logError ( msg ) {
var loggedMsg = ' Error : ' + msg;
$ log .error (loggedMsg);
return loggedMsg;
};
}
}) ();
| cs |
Use an Options File
[Style Y230 ]
JavaScript 코드에 lint를 걸기 위해 JS Hint를 사용하십시오. JS Hint 옵션을 반드시 정의하고 소스 코드 관리에 포함시켜야합니다.고급 옵션은 JS Hint docs 를 참조하십시오.
왜? : 소스 제어에 코드를 커밋하기 전에 먼저 경고가 올라갑니다.
왜? : 팀에 일관성이 생깁니다.1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61{" bitwise " : true ," camelcase " : true ," curly " : true ," eqeqeq " : true ," es3 " : false ," forin " : true ," freeze " : true ," immed " : true ," indent " : 4 ," latedef " : " nofunc " ," newcap " : true ," noarg " : true ," noempty " : true ," nonbsp " : true ," nonew " : true ," plusplus " : false ," quotmark " : " single " ," undef " : true ," unused " : false ," strict " : false ," maxparams " : 10 ," maxdepth " : 5 ," maxstatements " : 40 ," maxcomplexity " : 8 ," maxlen " : 120 ," asi " : false ," boss " : false ," debug " : false ," eqnull " : true ," esnext " : false ," evil " : false ," expr " : false ," funcscope " : false ," globalstrict " : false ," iterator " : false ," lastsemic " : false ," laxbreak " : false ," laxcomma " : false ," loopfunc " : true ," maxerr " : false ," moz " : false ," multistr " : false ," notypeof " : false ," proto " : false ," scripturl " : false ," shadow " : false ," sub " : true ," supernew " : false ," validthis " : false ," noyield " : false ," browser " : true ," node " : true ," globals " : {" angular " : false ," $ " : false}}Colored by Color Scriptercs
코딩 스타일을 확인하기 위해 JSCS를 사용해주세요. JSCS 옵션 파일을 반드시 정의하고 소스 파일 관리에 포함하도록하십시오. 고급 옵션은 JSCS docs 를 참조하십시오.
왜? : 소스 코드 관리에 파일을 덤하기 전에 첫 번째 경고가 오르게됩니다
왜? : 당신의 팀에 일관성이 생깁니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
| {
" excludeFiles " : [ " node_modules / ** " , " bower_components / ** " ,
" requireCurlyBraces " : [
" if " ,
" else " ,
" for " ,
" while " ,
" do " ,
" try " ,
" catch "
,
" requireOperatorBeforeLineBreak " : true ,
" requireCamelCaseOrUpperCaseIdentifiers " : true ,
" maximumLineLength " : {
" value " : 100 ,
" allowComments " : true ,
" allowRegex " : true
},
" validateIndentation " : 4 ,
" validateQuoteMarks " : " ' " ,
" disallowMultipleLineStrings " : true ,
" disallowMixedSpacesAndTabs " : true ,
" disallowTrailingWhitespace " : true ,
" disallowSpaceAfterPrefixUnaryOperators " : true ,
" disallowMultipleVarDecl " : null ,
" requireSpaceAfterKeywords " : [
" if " ,
" else " ,
" for " ,
" while " ,
" do " ,
" switch " ,
" return " ,
" try " ,
" catch "
,
" requireSpaceBeforeBinaryOperators " : [
" = " , " + = " , " - = " , " * = " , " / = " , " % = " , " << = " , " >> = " , " >>> = " ,
" & = " , " | = " , " ^ = " , " + = " ,
" + " , " - " , " * " , " / " , " % " , " << " , " >> " , " >>> " , " & " ,
" | " , " ^ " , " && " , " || " , " === " , " == " , " > = " ,
" <= " , " < " , " > " , " ! = " , " ! == "
,
" requireSpaceAfterBinaryOperators " : true ,
" requireSpacesInConditionalExpression " : true ,
" requireSpaceBeforeBlockStatements " : true ,
" requireLineFeedAtFileEnd " : true ,
" disallowSpacesInsideObjectBrackets " : " all " ,
" disallowSpacesInsideArrayBrackets " : " all " ,
" disallowSpacesInsideParentheses " : true ,
" validateJSDoc " : {
" checkParamNames " : true ,
" requireParamTypes " : true
},
" disallowMultipleLineBreaks " : true ,
" disallowCommaBeforeLineBreak " : null ,
" disallowDanglingUnderscores " : null ,
" disallowEmptyBlocks " : null ,
" disallowTrailingComma " : null ,
" requireCommaBeforeLineBreak " : null ,
" requireDotNotation " : null ,
" requireMultipleVarDecl " : null ,
" requireParenthesesAroundIIFE " : true
}
| cs |
vendor 라이브러리의 전역 변수에 대한 Angular 상수를 만들어주세요.
왜? : 글로벌이되어 버리는 vendor 라이브러리를 주입하는 방법을 제공합니다. 이는 구성 요소가있다 의존성을보다 쉽게 파악하여 (추상성의 파탄을 피) 코드 테스터 리티가 개선됩니다. 또한 이치에 맞는 것처럼, 이러한 요소를 모의 테스트 할 수 있습니다.
1
2
3
4
5
6
7
8
9
10
11
| // constants.js / * global toastr : false, moment : false * /
( function () {
' use strict ' ;
angular
.module ( ' app.core ' )
.constant ( ' toastr ' , toastr)
.constant ( ' moment ' , moment);
}) ();
| cs |
변경되지 않고 다른 서비스에 의존하지 않는 값에 대한 상수를 사용하십시오. 상수가 여러 애플리케이션에서 재사용되는 모듈 만 사용되는 경우 모듈 뒤에 정수와 알 파일 이름에서 모듈마다 파일 상수를 넣습니다. 이것이 필요한까지 메인 모듈의
constants.js
파일에 상수를 넣습니다.왜? : 변경 될지도 모른다 값은 비록 자주 않았다고해도 서비스에서 검색되어야합니다. 이렇게하면 소스 코드를 변경할 필요가 없습니다. 예를 들어, 데이터 서비스를위한 URL을 정수로 올려 놓을 때, Web 서비스에서로드하는 것이 더 좋은 장소가 될 것입니다.
왜? : 상수는 공급자를 포함한 Angular의 구성 요소에 이식 가능합니다.
왜? : 응용 프로그램이 다른 응용 프로그램에서 재사용 될 수있는 모듈로 분할 될 때 종속있는 상수를 각각의 모듈에서 유지하여 모듈이 혼자 상수를 운용 할 수 있도록 에해야합니다.
1
2
3
4
5
6
7
8
9
10
11
12
| // Constants used by the entire app angular
.module ( ' app.core ' )
.constant ( ' moment ' , moment);
// Constants used only by the sales module angular
.module ( ' app.sales ' )
.constant ( ' events ' {
ORDER_CREATED : ' event_order_created ' ,
INVENTORY_DEPLETED : ' event_inventory_depleted '
});
| cs |
일관된 스타일과 패턴을 준수하기 위해 파일 템플릿 또는 조각을 사용하십시오. 여기에 몇 가지 Web 개발의 편집기와 IDEs위한 템플릿이나 조각이 있습니다.
이 스타일과 지침에 따른 Angular의 조각
- Sublime Angular snippets 다운로드
- Packages 폴더에 넣어
- Sublime를 다시 시작
- JavaScript 파일 유형에서
TAB
에 이어 다음 명령을 치고 있습니다.
ngcontroller // Creates AN Angular controller ngdirective // Creates AN Angular directive ngfactory // Creates AN Angular factory ngmodule // Creates AN Angular module ngservice // Creates AN Angular 서비스 ngfilter // creates an Angular filter
이 스타일과 지침에 따른 Angular 파일의 템플릿이 SideWaffle 에 공개되어 있습니다.
- SideWaffle 에서 Visual Studio extension (vsix 파일)을 다운로드
- vsix 파일을 실행
- Visual Studio를 다시 시작
이 스타일과 지침에 따른 Angular 조각 및 파일 템플릿. WebStorm의 settings로 가져올 수 있습니다.
- WebStorm Angular file templates and snippets 다운로드
- WebStorm을 열고
File
메뉴를 열 - 메뉴 옵션에서
Import Settings
를 선택 - 파일을 선택하고
OK
를 클릭 - JavaScript 파일 유형에서
TAB
에 이어 다음 명령을 치고 있습니다.
ng - c // Creates AN Angular controller NG - f // Creates AN Angular factory NG - m // creates an Angular module
- 이 스타일과 지침에 따른 Angular 조각
apm install angularjs-styleguide-snippets
- Atom을 열고 Package Manager를 열 (Packages -> Settings View -> Install Packages / Themes)
- 'angularjs-styleguide-snippets'패키지를 검색
- 패키지를 설치하기 위해 'Install'을 클릭
- JavaScript 파일 유형에서
TAB
에 이어 다음 명령을 치고 있습니다.
ngcontroller // Creates AN Angular controller ngdirective // Creates AN Angular directive ngfactory // Creates AN Angular factory ngmodule // Creates AN Angular module ngservice // Creates AN Angular 서비스 ngfilter // creates an Angular filter
이 스타일과 지침에 따른 Angular의 조각
- Brackets Angular snippets 다운로드
- Brackets Extension 관리자 (File> Extension manager)
- 'Brackets Snippets (by edc)' 를 설치
- brackets 오른쪽에있는 전구를 클릭
Settings
를 클릭하여Import
- 파일을 선택하고 Choose the file and select to skip or override
Start Import
를 클릭
- JavaScript 파일 유형에서
TAB
에 이어 다음 명령을 치고 있습니다.
// These are full file snippets containing AN IIFE ngcontroller // Creates AN Angular controller ngdirective // Creates AN Angular directive ngfactory // Creates AN Angular factory ngapp // Creates AN Angular module setter ngservice // Creates AN Angular 서비스 ngfilter // creates an Angular filter // These are partial snippets intended to chained ngmodule // Creates AN Angular module getter ngstate // Creates AN Angular UI Router state defintion ngconfig // defines a configuration Phase function ngrun // defines a run Phase function ngroute // defines an Angular ngRoute 'when'definition ngtranslate // uses $ translate service with its promise
이 스타일과 지침에 따라 vim의 조각
- vim Angular snippets 다운로드
- neosnippet.vim 를 세트
- 조각 snippet 디렉토리에 복사
ngcontroller // Creates AN Angular controller ngdirective // Creates AN Angular directive ngfactory // Creates AN Angular factory ngmodule // Creates AN Angular module ngservice // Creates AN Angular 서비스 ngfilter // creates an Angular filter
이 스타일 가이드에 따른 Angular 응용 프로그램을 만드는 좋은 시작 지점으로 HotTowel yeoman generator 를 사용할 수 있습니다.
generator-hottowel 설치
npm install -g generator-hottowel
새 폴더를 만들고 그 디렉토리로 이동
mkdir myapp cd myapp
발전기의 실행
yo hottowel helloWorld
뷰와 수많은 작은 템플릿 및 지시문을 가지는 뷰의 조합으로 이루어진 뷰 사이의 탐색 흐름을 만들기 위해 클라이언트 사이드의 라우팅은 중요합니다.
클라이언트 사이드의 라우팅은 AngularUI Router 를 사용하십시오.
왜? : UI Router는 Angular 라우터가 가지고있는 모든 기능 플러스 중첩 된 라우팅 및 상태 등 몇 가지 추가 기능이 있습니다.
왜? : 구문은 Angular 라우터와 매우 유사하며 UI Router로 쉽게 이동할 수 있습니다.
- Note : 다음에 표시된대로
routerHelperProvider
같은 공급자를 이용할 수 있습니다. 그것은 run 단계에서 파일을 걸치고 state를 설정하는 데 도움이됩니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| // customers.routes.js angular
.module ( ' app.customers ' )
.run (appRun);
/ * @ngInject * /
function appRun ( routerHelper ) {
routerHelper.configureStates (getStates ());
}
function getStates () {
return [
{
state : ' customer ' ,
config : {
abstract : true ,
template : ' <ui-view class = "shuffle-animation"/> ' ,
url : ' / customer '
}
}
];
}
| cs |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
| // routerHelperProvider.js angular
.module ( ' blocks.router ' )
.provider ( ' routerHelper ' , routerHelperProvider);
routerHelperProvider $ inject = [ ' $ locationProvider ' , ' $ stateProvider ' , ' $ urlRouterProvider ' ];
/ * @ngInject * /
function routerHelperProvider ( $ locationProvider , $ stateProvider , $ urlRouterProvider ) {
/ * jshint validthis : true * /
this $ get = RouterHelper;
$ locationProvider.html5Mode ( true );
RouterHelper $ inject = [ ' $ state ' ];
/ * @ngInject * /
function RouterHelper ( $ state ) {
var hasOtherwise = false ;
var 서비스 = {
configureStates : configureStates,
getStates : getStates
};
return 서비스;
///////////////
function configureStates ( states , otherwisePath ) {
states.forEach ( function ( state ) {
$ stateProvider.state (state.state, state.config);
});
if (otherwisePath && ! hasOtherwise) {
hasOtherwise = true ;
$ urlRouterProvider.otherwise (otherwisePath);
}
}
function getStates () { return $ state.get ();}
}
}
| cs |
뷰가 존재하는 모듈에서보기위한 라우팅을 정의하십시오. 각각의 모듈은 모듈 내의 뷰에 대한 라우팅을 포함한다.
왜? : 각각의 모듈이 독립적으로 성립한다.
왜? : 모듈 삭제되고 추가 될 때 응용 프로그램이 존재하는 뷰를 나타내는 라우팅만을 포함하는 것입니다.
왜? :이 것은 부모없는 라우팅이 가능하게 우려를 가지지 않고 응용 프로그램의 일부분을 활성화하거나 비활성화 할 것을 쉽게합니다.
자동 태스크의 생성에 Gulp 또는 Grunt 를 사용하십시오. Gulp는 구성을 코딩에 엎드려서 할 수 있습니다. 한편, Grunt 코드를 구성에 엎드려서 할 수 있습니다. 개인적으로 가독성 또한 쓰기 쉬운 Gulp을 좋아하지만 양자 모두 훌륭합니다.
내 Gulp Pluralsight course 에서 Gulp 정보 및 작업의 자동화에 대해 더 배울 수 있습니다.
기타 모든 응용 프로그램의 JavaScript 파일에 앞서 모듈 정의 파일
* .module.js
을 목록 화하는 자동화 작업을 사용하십시오.왜? : Angular 그들이 사용되기 전에 모듈 정의를 등록해야합니다.
왜? :* .module.js
처럼 특정 패턴으로 명명 된 모듈은 쉽게 잡아 또한 목록의 맨 위에 열거 할 수 있습니다.
1
2
3
4
5
6
7
| var ClientApp = ' ./src/client/app/ ' ;
// Always grab module Files first var Files = [
clientApp + ' ** / *. module.js ' ,
clientApp + ' ** / *. js '
];
| cs |
복잡한 객체 그래프의 모든 속성을 검색과 같은 필터의 사용을 피해주십시오. 선택된 속성에 필터를 사용하십시오.
왜? : 필터는 쉽게 오용됩니다. 적절히 이용되지 않은 경우, 예를 들어 필터가 크고 깊은 개체 그래프를 읽어내는 시간 등 성능에 부정적인 효과가 있습니다.
30. Angular docs
기타 정보 API 참조, 내용은 Angular documentation 을 확인하십시오.
Open an issue first to discuss potential changes / additions. If you have questions with the guide, feel free to leave them as issues in the repository. If you find a typo, create a pull request. The idea is to keep the content up to date and use github 's native feature to help tell the story with issues and PR 's, which are all searchable via google. Why? Because odds are if you have a question, someone else does too! You can learn more here at about how to contribute.
By contributing to this repository you are agreeing to make your content available subject to the license of this repository.
Process
1. Discuss the changes in a GitHub issue.
2. Open a Pull Request, reference the issue, and explain the change and why it adds value.
3. The Pull Request will be evaluated and either merged or declined.
'Develop > Front-End' 카테고리의 다른 글
[FB]페이스북 로그인 (0) | 2020.06.23 |
---|---|
카카오로그인 (0) | 2020.06.23 |
Facebook 로그인 연동 error (0) | 2020.05.06 |
Digging into Angular’s “Controller as” syntax by Todd Motto (0) | 2016.08.05 |
Cordova (0) | 2016.08.05 |