1. 문서 내용에 대해
-
이 문서에서는 Yeoman 을 통해 자신만의 app generator 모듈을 생성하는 방법에 대해 알아볼 것이다.
-
Yeoman 은 공식 홈페이지를 통해, 이를 시작하기 위한 내용을 제공하고있다.
-
이 문서의 내용은 MAC 환경을 기준으로 작성되어있다.
2 app generator 개발 환경 구축
-
generator-generator 모듈은 사용자가 자신만의 app generator 모듈을 개발할때, 그 기반 설계를 도와주는 Yeoman generator 모듈 중 하나이다.
- 반드시 이 구조를 따라갈 필요는 없겠지만, generator-generator 모듈은 어차피 기본 골격만 제공하므로, 해당되는 부분에 대해서는 동일하게 따라가도 좋을 듯 하다.
-
generator-generator 모듈을 설치한다.
sudo npm install -g generator-generator
-
설치된 generator-generator 모듈을 통해 생성할 app generator 모듈의 기반을 생성한다.
yo generator
-
생성할 app generator 모듈의 [base-name] 을 위와 같이 입력 후 설치를 완료하면, 입력한 [base-name] 을 기준으로 현재 위치에 app generator 모듈 폴더(./generator-cmtech)가 생성된다.
- [base-name]: cmtech
-
생성된 app generator 모듈 폴더(./generator-cmtech) 이름은 아래와 같은 형식으로 생성되며, Yeoman 은 이후
yo [base-name]
명령 실행 시 이 [base-name] 이 기준이된 app generator 모듈 폴더를 File system 상에서 찾아 실행하게될것이다.-
생성된 app generator 모듈 폴더 이름: generator-[base-name]
-
app generator 모듈 설치 명령: yo [base-name]
-
-
개발중인 app generator 모듈을 링크를 통해 설치한다.
-
정확히 말하면 사용자 시스템의 global node module 위치에, 개발중인 app generator 모듈(./generator-cmtech) 폴더의 링크를 만들어, npm 모듈을 설치하는것과같은, 환경을 만들어주는것이다.
-
먼저 global node module(/usr/local/lib/node_modules) 위치로 이동하여, 생성된 app generator 모듈 폴더를 링크 한다.
// global node module 위치로 이동한다. cd /usr/local/lib/node_modules // app generator 모듈 폴더를 심볼릭 링크한다. sudo ln -s /Users/sgjeon/htdocs/gitrepos/generator-cmtech generator-cmtech
그 다음 npm list 명령을 통해 app generator 모듈이 제대로 설치(링크)되었는지 확인해본다.
확인되었다면,
yo [base-name]
명령을 통해, app generator 모듈이 제대로 설치되는지 확인한다.
-
3. app generator 개발 포인트
-
package.json 파일 설정
-
아래는 app generator 모듈 폴더안의 package.json 파일 내용이다.
{ "name": "generator-cmtech", "version": "0.0.0", "description": "cmtech generator", "license": "MIT", "main": "app/index.js", "repository": "mohwa/generator-cmtech", "author": { "name": "mucha", "email": "", "url": "https://github.com/mohwa" }, "scripts": { "test": "mocha" }, "files": [ "generators" ], "keywords": [ "yeoman-generator" ], "dependencies": { "yeoman-generator": "^0.19.0", "chalk": "^1.0.0", "yosay": "^1.0.2" }, "devDependencies": { "mocha": "*" } }
-
name property 는 반드시 generator- 라는 접두사를 가져야한다.
- 예: generator-cmtech
-
Yeoman 에서 제공하는 generator-page 에 listed 되기 위해서는 keywords property 와 description property 를 반드시 서술해야한다.
- keywords property 에는 예제와 같이 ”yeoman-generator” 를 할당해준다.
-
-
Folder tree
-
Yeoman 은 아래와 같은 두 가지 폴더 구조를 제공하고있다.
-
./ 폴더 내부로 가용한 default generator 및 sub-generator 를 만들어내는 구조
├───package.json ├───app/ │ └───index.js └───router/ └───index.js
-
./generators 폴더 내부로 가용한 default generator 및 sub-generator 를 만들어내는 구조(개인적으로 이 폴더 구조를 선호한다)
├───package.json └───generators/ ├───app/ │ └───index.js └───router/ └───index.js
-
default generator 및 sub-generator 호출 방법
-
default generator 호출 방법
-
yo [base-name]
명령으로 실행하며, 이로인해 ./generators/app/ 디렉토리 안의 index.js 파일이 호출된다. -
예: yo cmtech
-
-
sub-generators 호출 방법
-
yo [base-name]:[sub-command]
명령으로 실행하며, 이로인해 ./generators/[sub-command]/ 디렉토리 안의 index.js 파일이 호출된다. -
예: yo cmtech:router
-
-
-
-
base generator 확장하기
-
yeoman-generator 모듈을 통해 base generator 를 생성할 수 있으며, 이것을 확장하여 자신만의 app generator 모듈 기능을 만들어낸다.
// app/index.js 내부 // base generator 를 생성한다. var generators = require('yeoman-generator'); // base generator 를 확장한다. module.exports = generators.Base.extend({ constructor: function () { generators.Base.apply(this, arguments); // This makes `appRootFolder` a required argument. this.argument('appRootDir', { type: String, required: true }); } });
-
-
Overwriting(기존 property 를 다시쓰는 행위) the constructor
-
특정 generator 메서드들은 constructor function 내부에서만 호출해야한다. 만약 그렇지 않을경우, 해당 기능이 완벽히 수행되지 않을 수 있다.
-
예를들어, 사용자가 Command Line 을 통해 입력한 arguments 를 처리하는 this.argument 메서드 호출 시, 해당 코드가 호출되는 위치에 따라 다른 결과를 반환되게된다.
-
먼저 테스트위해
yo cmtech —help
명령을 실행한다.// cmtech generator 를 --help 옵션과 함께 실행한다. yo cmtech --help
-
argument 메서드가 constructor function 내부에서 호출된 경우.
// base generator 를 확장한다. module.exports = generators.Base.extend({ constructor: function () { generators.Base.apply(this, arguments); // This makes `appRootFolder` a required argument. this.argument('appRootDir', { type: String, required: true }); } });
Yeoman 이 arguments 에 대한 상세 도움말을 제공해준다.
argument 메서드가 constructor function 외부에서 호출된 경우.
// base generator 를 확장한다. module.exports = generators.Base.extend({ initializing: function(){ this.argument('appRootDir', { type: String, required: true }); } });
arguments 에 대한 도움말이 제공되지 않는다.
-
-
GENERATOR RUNTIME CONTEXT
-
The run loop
-
Yeoman 은 run loop 라는 queue system 을 가지며, 이것은 실행하려는 메서드 그룹에 대한 우선 순위를 제공해준다.
- 또한 run loop 다루기위해 Grouped-queue 라는 모듈을 사용하고있다.
-
이 우선 순위는 Yeoman 이 제공하는 특별한 프로토타입 메서드 이름(priority name)으로만 사용된다.
- Yeoman 이 제공하는 priority name 리스트는 아래와 같다.
-
priority name 일 경우.
'use strict'; var yeoman = require('yeoman-generator'); var chalk = require('chalk'); var yosay = require('yosay'); module.exports = yeoman.generators.Base.extend({ initializing: { init: function() { console.log('call by init method 1'); }, end: function(){ console.log('call by end method 2'); } } });
-
정의된 메서드 그룹이 전부 실행된다.
-
priority name 이 아닐경우.
'use strict'; var yeoman = require('yeoman-generator'); var chalk = require('chalk'); var yosay = require('yosay'); module.exports = yeoman.generators.Base.extend({ custom_method: { init: function() { console.log('call by init method 1'); }, end: function(){ console.log('call by end method 2'); } } });
정의된 메서드가 실행되지 않는다.
또한 priority name 이 아닐경우, 아래와 같이 Object 가 아닌 Function 타입으로 정의해야한다.
'use strict'; var yeoman = require('yeoman-generator'); var chalk = require('chalk'); var yosay = require('yosay'); module.exports = yeoman.generators.Base.extend({ custom_method: function(){ console.log('call by custom_method method'); } });
-
-
-
Template 엔진 사용하기
-
Yeoman 은 ejs template 엔진을 사용하며, copyTpl 메서드와 같은 템플릿 관련 메서드들을 제공하고 있다.
-
아래 코드는 메서드 사용에 대한 간단한 예제이며, .html 파일외에, APP 을 구성하는 기반 파일인 _package.json 또는 _gruntfile.js 와 같은 파일에도 동일하게 적용할 수 있다.
generators.Base.extend({ writing: function () { this.fs.copyTpl( this.templatePath('index.html'), this.destinationPath('public/index.html'), { title: 'Templating with Yeoman' } ); } });
-
template 엔진을 통해 아래와 같이 출력된다.
<html> <head> <title>Templating with Yeoman</title> </head> </html>
-
추가적으로 의존성을 관리하는 파일인 _bower.json 파일에 적용된 내용이다.
<% var ngVer = "1.2.26" %> { "name": "<%= env.appName %>", "description": "<%= env.appName %> package manager", "homepage": "http://www.cmt-korea.com/", "author": { "name": "sgjeon" }, "ignore": [ "**/.*", "node_modules", "bower_components" ], "dependencies": { }, "devDependencies": { "angular": "<%= ngVer %>", "angular-animate": "<%= ngVer %>", "angular-cookies": "<%= ngVer %>", "angular-route": "<%= ngVer %>", "angular-resource": "<%= ngVer %>", "angular-sanitize": "<%= ngVer %>", "requirejs": "2.1.14", "jquery": "2.1.1", "malihu-custom-scrollbar-plugin": "3.0.8", "jquery-ui": "1.11.2", "json3": "3.3.2", "linqjs": "", "xml2json": "", "purl": "2.3.1", "jquery-mousewheel": "3.0.6", "socket.io-client": "1.3.5", "console.image": "", "enquire": "2.1.2", "angular-local-storage": "0.1.5", "matchMedia": "0.2.0", "jquery.browser": "0.0.7" } }
-
-
전역 configurations 파일 관리하기
-
Yeoman 은 숨김 파일인 .yo-rc.json 파일을 통해 전역 configurations 을 관리할 수 있으며, 또 그것을 관리하기 위한 Yeoman Storage API 를 제공하고있다.
-
아래는 기본적인 .yo-rc.json 파일 구조이다.
{ "generator-cmtech": { "key": "value" } }
-
4. 정리하며
-
아래 URL 은 현재 개발중인 사이트(AngularJS 사용)의 app generator 초기 버전이며, 설계시 참고할 수 있을 듯하여 공유드립니다.(현재는 테스트 버전입니다)