Gulp와 Bower

Gulp와 Bower

yarn이 bower 지원을 중단하고 yarn이 bower_components를 node_modules 로 이동함에 따라 bower 대신 npm (yarn), webpack 으로 전환이 되고 있다. [^Using Bower with Yarn], [^Migrate from Bower to npm and Webpack]

Bower 란

  • 자바스크립 모듈의 의존성 관리. 예) angularjs, angular-material 등 의존성 관리
  • 트위터에서 만든 프론트 엔드의 패키지를 관리해주는 도구이다.
  • https://bower.io
  • Gulp 빌더

Bower

javascript라이브러리 뿐만 아니라 css도 포함되는 ui 컴퍼넌트들은 해당 라이브러리들의 경로 문제도 있어 다양한 라이브러리 사용시
의존성 문제가 더더욱 발생된다. 이러한 점을 쉽게 bower를 이용해 해결이 가능하며, 사용하는 라이브러리들의 업데이트 사항도 체크가 가능하니 매우 편하다.

bower 은 gulp, npm 에서 스크립트로 실행해서 프로젝트의 로컬로 설치해도 무방하다.

1
npm i bower

Bower 명령어

bower를 이용하여 패키지를 설치를 하고 싶은경우 bower install이라는 명령어를 이용하면 패키지가 설치가 가능하다.

1
bower install <패키지명>

만약 jquery를 설치하고 싶은 경우는 아래와 같이 입력하면된다.

1
bower install jquery

특정 버전을 설치하고 싶은 경우는 뒤에 #버전을 입력하면 가능하다.

1
bower install jquery#1.11.1

패키지를 삭제하고 싶은경우는 install 대신 uninstall로 입력한다.

1
bower uninstall <패키지명>

Bower.json

bower의 경우도 npm과 마찬가지로 패키지 명시를 파일로 관리하게된다. npm은 package.json을 이용하여 관리하였지만 bower는 bower.json 파일로 관리하게되며 마찬가지로 bower init 명령어를 통하여 쉽게 생성이 가능하다. 세부 내역은 bower.json 에서 확인할 수 있다.

1
2
3
4
5
{
"name": "packageName",
"version": "0.0.1",
"ignore": ["**/.*", "node_modules", "components"]
}
  • Name
    필수값이며, 패키지 명칭이다 npm과 마찬가지고 패키지의 명칭을 이용하여 install이 가능하다.
  • version
    패키지 버전정보 사실 bower로 배포하는게 아니라면 크게 의미없는 항목이다.
  • ignore
    bower가 설치할때 무시할 항목이다.
  • dependencies/devDependencies
    의존성 관리 항목이다. dev가 붙은건 개발시에만 필요한 의존성 라이브러리로 bower에 배포할게 아니라면 크게 구분할 의미가 없다.

.bowerrc

.bowerrc 파일은 bower 가 실행될 때 항상 먼저 실행이 되는 기본적이 내용을 정의하게 된다. bower config 에 세부 내역을 확인할 수 있다.



Gulp

gulp-cli, 를 글로벌로 설치하고 프로젝트에서 gulp, bower 모듈을 설치한다.

gulp-cli 를 글로벌로 설치한다.

1
npm i -g gulp-cli

gulpfile.js

를 만들고 필요한 task 들을 정의

proj 폴더 루트에 gulpfile.js 를 작성한다.

1
2
3
4
5
6
7
var gulp = require("gulp");
var ts = require("gulp-typescript");
var tsProject = ts.createProject("tsconfig.json");

gulp.task("default", function () {
return tsProject.src().pipe(tsProject()).js.pipe(gulp.dest("dist"));
});

첫번째 프로젝트

이 bower, gulp 이용한 프로젝트 폴더 구조는 보통 다음과 같다.

1
2
3
4
5
6
7
8
./myproject/
|______bower_components/
|______build/
|______node_modules/
|______src/
|______bower.json
|______gulpfile.js
|______.bowerrc

프로젝트 폴더에서 package.json 파일을 만들기 위해 초기화 한다.

1
2
3
mkdir myproject
cd myproject
git init

.gitignore 파일

1
2
3
bower_components/**
node_modules/**
build/**

gitignore 파일을 추가하고 커밋

1
2
git add .gitignore
git commit -m 'add gitignore'

npm init

1
npm init

이렇게 생성된 package.json 은,

1
2
3
4
5
6
7
8
9
10
11
{
"name": "myproject",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
}

이어서 typescript, gulp, gulp-typescript, bower 를 설치하고 dev 의존성으로 저장한다.

1
2
npm install --save-dev typescript gulp gulp-typescript
npm install --save-dev bower

package.json에 의존성 패키지가 명시되면 패키지 버전이 명시되는데 이 방법을 Semantic Versioning(Semver)라고 한다. started/semantic-versioning 참고한다.

bower 스크립트

bower init 를 실행해서

1
bower init

기본값으로 bower.json 파일을 생성하면,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
name: 'bower_gulp_exam',
description: '',
main: 'index.js',
authors: [
'gangtai <gangtai.goh@gmail.com>'
],
license: 'ISC',
homepage: '',
ignore: [
'**/.*',
'node_modules',
'bower_components',
'test',
'tests'
]
}

그리고 .bowerrc 파일에 의존성 파일들을 다운로드 할 디렉터리만 설정한다.

1
2
3
{
"directory": "bower_components"
}

bower 명령어를 통해서 angular-material, angular-loader, angular-route 패키지를 추가한다.

1
bower install --save angular-material angular-loader angular-route

패키지가 추가된 bower.json 은 다음 같다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
{
"name": "blog-npm",
"description": "Npm + Bower + Gulp for client web development",
"main": "index.js",
"authors": [
"road <roadkh@gmail.com>"
],
"license": "ISC",
"homepage": "",
"ignore": [
"**/.*",
"node_modules",
"bower_components",
"test",
"tests"
],
"dependencies": {
"angular-material": "^1.0.9",
"angular-loader": "^1.5.7",
"angular-route": "^1.5.7"
}
}

프로젝트 태스크 관련

gulp는 빌드를 위한 task를 정의하므로 여기서 myproject에서 처리할 태스크는 다음 같다:

  • (1) bower_components 하위에 있는 모듈들을 디렉터리 구조를 유지하면서 그 안에 있는 js와 css를 build/assets/ext 디렉터리로 복사합니다. 이때 해당 모듈의 minify 된 js와 css가 있으면 해당 js와 css를 복사하고 없으면 일반 js와 css를 복사합니다.

  • (2) src/js 하위에 있는 자바스크립트 파일을 minify하고 파일명을 .min.js 형식으로 변경한 후에 build/assets/js 에 디렉터리구조를 유지하면서 복사합니다.

  • (3) src/css 하위에 있는 css 파일을 읽어서 지정된 브라우저 설정에 맞는 처리를 진행하고 minify 한 후에 파일명을 .min.css 형식으로 변경하여 build/assets/css 에 디렉터리 구조를 유지하면서 복사합니다.

  • (4) src/html 에 있는 html 파일을 디렉터리 구조를 유지하면서 build/ 폴더로 복사합니다.
    목업 작업 중 위에 지정한 작업이 계속해서 이루어져서 일일이 명령어를 치지 않도록 합니다.

  • 마지막으로 build 디렉터리를 지우는 명령도 있었으면 합니다.

이 태스크를 다루기 위한 모듈을 추가로 설치한다. 추가 할 모듈은 아래와 같습니다:

  • gulp-load-plugins : 지금부터 설치할 모든 npm 중 gulp 관련 모듈 패키지들을 쉽게 사용.
  • bower-main : bower_components 폴더의 파일에 대한 처리를 위해 추가.
  • gulp-rename : 파일명을 바꾸기 위해 추가.
  • gulp-uglify : 자바스크립트의 minify 처리를 위해 추가.
  • gulp-autoprefixer : 지원하고자 하는 브라우저의 정보를 설정해서 적절한 처리를 자동으로 진행하게 하는 모듈 패키지. https://www.npmjs.com/package/gulp-autoprefixer 의 내용을 참고.
  • gulp-uglifycss : CSS 파일의 minify 처리를 위해 추가.
  • gulp-watch : 작업중에 작업된 내용을 실시간으로 gulp 에 설정한 내용이 실행되도록 하기 위해 추가.
  • del : build 디렉터리를 지우는 clean task 를 만들기 위해 추가.

태스크에 사용할 패키지를 설치한다.

1
npm i -D bower-main gulp-load-plugins gulp-rename gulp-uglify  gulp-autoprefixer gulp-uglifycss gulp-watch del

gulp-clean-dest

설치한 후 package.json 에 다음 같이 추가된다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
"devDependencies": {
"bower": "^1.7.9",
"bower-main": "^0.2.14",
"gulp": "^3.9.1",
}

devDependencies {
"gulp-autoprefixer": "^3.1.0",
"gulp-load-plugins": "^1.2.4",
"gulp-rename": "^1.2.2",
"gulp-uglify": "^1.5.4",
"gulp-uglifycss": "^1.0.6",
"gulp-watch": "^4.3.8"
}

Http server

http-server, lite-server

npm 으로 HTTP 서버를 띄워서 작업을 쉽게 할 수 있도록 npm 에 http-server 의존성 추가

1
npm i -g http-server

lite-server는 Node 서버 개발시 실시간 리로딩과 browser-sync (lite-server의 하부 모델)를 이용해 HTML, CSS, JS 를 테스트한다.

https://www.npmjs.com/package/lite-server

1
$ npm i -D lite-server
lite-server 이용

We need a server and live-reload so we need to install lite-server:

npm install —save-dev lite-server
Edit package.json file and add this script:

“scripts”: {
“start”: “lite-server”
}

npm install –save-dev concurrently

Edit package.json scripts:

“scripts”: {
“start”: “concurrently ‘lite-server’ ‘webpack — watch’”
}

gulfile.js 관련

앞서 설치한 태스크를 사용한 프로젝트 태스크를 gulpfile.js 에 선언한다.

gulp 모듈을 들여오고, 작업을 진행할 source 디렉터리와 결과물을 보관할 build 디렉터리를 지정한다.

1
2
3
4
var gulp = require("gulp");

var src = "./src/";
var dest = "./build/";

npm 에 추가한 모듈들을 일일이 require하지 않고 사용하기 위한 처리입니다.
예를 들어 bower-main의 경우는 plugins.bowerMain() 식으로 사용이 가능합니다.
gulp-로 시작하는 모듈들의 경우는 gulp-를 뺀 나머지로 사용가능합니다.

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
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
var plugins = require("gulp-load-plugins")({
pattern: ["gulp-*", "gulp.*", "bower-main"],
replaceString: /\bgulp[\-.]/,
});

// Minify & copy JS
/*
자바스크립트에 대한 처리를 진행합니다.
{base: ''} 옵션을 넣은 이유는 이렇게 해야 디렉터리 구조를 유지한 상태로 복사합니다.
그렇지 않을 경우에는 build 디렉터리에 그대로 파일을 복사합니다.
혹시 concat모듈을 이용해서 하나의 거대 파일로 합칠 경우에는 위 옵션은 필요없습니다.
처리의 내용은 src/js/ 하위의 모든 js 파일을 읽어서 이름을 .min.js 로 변경하고
minify를 진행한 후에 build/assets/js 로 복사하라는 내용입니다.
*/
function processJS() {
return gulp
.src(src + "js/**/*.js", { base: src + "js/" })
.pipe(plugins.rename({ suffix: ".min" }))
.pipe(plugins.uglify())
.pipe(gulp.dest(dest + "assets/js"));
}
// gulp에 scripts라는 task로 지정합니다.
gulp.task("scripts", processJS);

// Minify & copy CSS
/*
CSS 파일에 대한 처리를 진행합니다. 자바스크립트와 거의 동일한데 autoprefixer 부분만 특징적입니다.
아래 설정은 모든 브라우저의 최근 2개버전을 처리하기 위한 css 처리를 하라는 내용입니다.
*/
function processCss() {
return gulp
.src(src + "css/**/*.css", { base: src + "css/" })
.pipe(
plugins.autoprefixer({
// browsers: ['last 2 Chrome versions', 'last 2 Firefox versions', 'last 2 Android versions', 'last 2 ChromeAndroid versions'],
browsers: ["last 2 versions"],
cascade: true,
})
)
.pipe(plugins.rename({ suffix: ".min" }))
.pipe(plugins.uglifycss())
.pipe(gulp.dest(dest + "assets/css"));
}
// gulp에 css라는 task로 지정합니다.
gulp.task("css", processCss);

// Copy HTML
/*
HTML 파일들을 복사합니다.
*/
function processHtml() {
return gulp
.src(src + "html/**/*.html", { base: src + "html/" })
.pipe(gulp.dest(dest));
}
gulp.task("html", processHtml);

// Copy Vendor JSS & CSS from bower_components
/*
bower_components 디렉터리에 있는 js와 css 들을 복사합니다.
bower_main 모듈의 처리 결과는 minified, minifiedNotFound, normal 있는데 내용은
minified : minify 처리된 파일
normal : 일반 파일
minifiedNotFound : minify 처리된 파일이 없는 파일들의 일반 파일
입니다.
각 파일들의 파일명 리스트를 모두 합쳐서 디렉터리 구조를 유지시키면서 assets/ext 로 복사합니다.
*/
function processExternal() {
var scriptBowerMain = plugins.bowerMain("js", "min.js");
var cssBowerMain = plugins.bowerMain("css", "min.css");
var mapBowerMain = plugins.bowerMain("js", "min.js.map");
return gulp
.src(
scriptBowerMain.minified
.concat(scriptBowerMain.minifiedNotFound)
.concat(cssBowerMain.minified)
.concat(cssBowerMain.minifiedNotFound)
.concat(mapBowerMain.minified),
{ base: "./bower_components" }
)
.pipe(gulp.dest(dest + "assets/ext"));
}
// gulp 에 external 이라는 task 로 지정합니다.
gulp.task("external", processExternal);

// Watch for changes in files
/*
실시간 감시를 위한 task 등록입니다.
지정한 디렉터리를 감시하고 있다가 추가/삭제/변경 등이 발생할 경우에는 지정한 함수를 호출합니다.
원래 gulp.watch 가 있는데 이 경우는 변경사항은 감지가 되지만 추가/삭제는 감지가 되지 않습니다.
그래서 gulp-watch 모듈을 이용했습니다.
*/
gulp.task("watch", function () {
plugins.watch(src + "js/**/*.js", processJS);
plugins.watch(src + "css/**/*.css", processCss);
plugins.watch(src + "html/**/*", processHtml);
plugins.watch("./bower_components/**/*", processExternal);
});

// Default Task 입니다.
gulp.task("default", ["scripts", "css", "html", "external", "watch"]);

/**
* clean build.
* 원래는 default task에 넣어서 gulp가 시작될 때 깨끗하게 build 디렉터리를 비우게 만들고 싶었는데,
* 오류가 발생해서 잘 안됩니다. 뭔가 방법이 있을텐데 쉽게 찾아지지는 않네요.
*/
gulp.task("clean", function (cb) {
plugins.del(["build/**"], cb);
});

run

그리고 package.json의 scripts 부분에 아래와 같은 내용을 추가하고, npm install 명령을 이용해서 최초 구성을 할 때 bower install 명령이 함께 실행되도록 한다.

위 두 가지 내용을 scripts 의 postinstall 과 start 속성으로 추가합니다.

1
2
3
4
5
6
7
...
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"postinstall": "bower install",
"start": "http-server -a localhost -p 8000 -c-1 ./build"
},
...

최종적으로,

필요 패키지가 설치됐는지 확인하고,

1
npm install

이제 gulp 빌드를 시작하면 src 디렉터리를 만들고, sample 디렉토리에 디렉토리 js, css, html 를 src 디렉터리에 복사한다.

1
gulp

gulp로 빌드 태스크를 시작하고 Ctrl+C로 종료한다.

그리고 build 밑에 소스가 생성되었는지 확인다.

1
2
3
4
$ ll build/
assets/
index.html
view/

http-server를 실행한다.

1
npm start

angular-seed

angularjs 기본 프로젝트 구성을 가진 저장소로 bower, gulp 기반으로 제공된다.

1
git clone https://github.com/angular/angular-seed.git

참조