서문에
5 분은 어제의 개그입니다, 저를 때리지 마세요,哈哈
一.왜 gulp 인가?
빌드 도구 (번들 도구) 하면, 슬픈 grunt 가 생각납니다. 그리고 작년 5 월의 그 노트: [Grunt 튜토리얼](/articles/grunt 튜토리얼/)
선택 가능한 빌드 도구는 매우 많습니다:
-
설정 파일을 미친 듯이 작성하는 grunt
-
pipe 하고 pipe 하는 gulp
-
로고가 매우 훌륭한 webpack
-
에둘러 말하는 것을 싫어하는 npm scripts
-
시대를 초월했다고 자칭하는 rollup
-
...
하지만, 왜 gulp 인가?
먼저, grunt 는 시대에 뒤떨어졌습니다. 작년 5 월에는 grunt 가 아직 어떻게든 버텼습니다 (플러그인 수가 gulp 보다 훨씬 많았기 때문에, 그 노트가 있었습니다), 지금은 더 이상 장점이 없습니다. 플러그인 수는 더 이상 gulp 의 단점이 아닙니다
npm scripts 가 말하듯이, pipe 는 gulp 의 오리지널이 아니며, 운영체제가 원래 지원합니다. 그래서 npm scripts 의 이념은shell 명령어에 직면하고, 불필요한 추상층을 제거하는것입니다 (grunt, gulp...). 예를 들어 gulp-jshint, 직접 jshint 가 제공하는 cli 를 실행하면 되는데, gulp 가 뭐하러 필요합니까?
webpack/rollup 에 대해서는, grunt/gulp 와 비슷할 것입니다 (둘 다 npm scripts 의 눈에는 불필요한 추상층), 매일 빌드 도구를 바꿀 필요는 없습니다. 그래서, gulp 를 선택한 것은 단순히비용때문입니다 (팀이 원래 사용 중이었음)
二.npm scripts
설계 이념으로 보면, npm scripts 가 더 앞서 있는 것 같습니다. 몇 가지 이유:
-
중간 추상층을 제거하고, 직접 package 가 제공하는 cli 를 사용. 플러그인 업데이트를 기다리지 않고 package 의 신기능을 사용 가능
-
구조가 더 간단하여, 디버깅 복잡도를 낮춤 (package 의 문제?
설정 의 문제?플러그인 버전/플러그인 자체 의 문제?프로젝트 코드 의 문제?) -
운영체제가 실행할 수 있는 모든 스크립트를 실행 가능 (python, bash 스크립트 등. gulp + shelljs 가 어떻게든 쫓아가고, grunt 는 뒤쳐짐)
-
플러그인은 없지만, "플러그인" 수는 가장 많음 (누가 플러그인 써주기를 기다림?명령줄에서 실행할 수 있는 모든 스크립트가 모두 "플러그인")
물론, 몇 가지 단점도 존재합니다:
-
package.json 에 주석을 추가할 수 없음. readme 에 씀?그래도 좀 괴로움
-
명령줄을 조금은 알아야 함. npm 이 1000 개 이상의 기본 명령어를 캡슐화했지만, "폴더 삭제"에서
rm -rf에서 rimraf 까지의 프로세스는 너무도 굴곡져서,常用 명령어 이해는 필수 -
변수를 지원하지 않음. 환경 변수와 모든 스크립트를 지원, 충분함 (
"build": "node bin/build.js")
예:
// package.json
{
...
"scripts": {
// basic
"watch-test": "mocha --watch --reporter spec test",
"test": "mocha \"src/**/*.test.js\" --require test/setup.js --compilers js:babel-register",
// pipe
"build-js": "browserify -t reactify app/js/main.js | uglifyjs -mc > static/bundle.js",
// and(&&)、or(||)
"build": "npm run build-js && npm run build-less",
// concurrent
"watch": "npm run watch-js & npm run watch-less & npm run watch-server"
}
}
더 복잡한 명령어는 bash shell 스크립트를 쓰거나, node + shelljs 로,余分한 것은 없습니다
三.node 명령줄 도구를捏造하다
글로벌 명령어를 커스터마이즈하고 싶습니까?어떤 디렉토리에서도 실행 가능?실제로 매우 쉽습니다
-
nodejs 코드를编写하고, Shebang 추가 (파일 첫 행에
#!/usr/bin/env node추가, node 로 이 파일을 실행함을 나타냄),xxx.js로 저장 -
npm init또는 직접package.json을 손으로 씀 -
package.json 을修改하고,
"bin": {"hoho": "xxx.js"}추가 -
npm link로 로컬 package 를 글로벌에 link (windows 환경변수 path 와 유사)
중요한 스텝은 이렇지만, 몇 가지 문제가 존재합니다:
-
명령어를 어떻게 크로스플랫폼하는가?(windows, unix)
-
명령줄 파라미터를 어떻게 획득하는가?
-
어떻게
gulp를 사용하는가?
shelljs 모듈은 크로스플랫폼 명령어를 제공; yargs 모듈은 명령줄 파라미터를 획득 가능; gulp 를 사용하려면 npm install gulp --save-dev 로로컬에 gulp 를 설치하고 의존을 추가; 더욱이, 명령줄에서 오색찬란한 것을 출력하고 싶다면, colors 모듈도 사용 가능
주의: 로컬에 gulp 를 설치하는 것은 필수입니다. gulp 의 설계 이념은 모든 package 가 하나의 글로벌 gulp 에 의존하는 것을 원하지 않기 때문에, require('gulp') 하려면 로컬에 하나 설치해야 하며, 파일이 많아서 별로 편안하지는 않지만, 더 유연합니다
명령줄 도구는 제 0 보로, 중요하지만 결정적이지는 않습니다. 구체적인 스텝은 이걸 참조: Nodejs 명령줄 도구 제작
四.gulp 로 워크플로우 최적화
여기서의 "워크플로우"는기본적인 번들 스텝 (컴파일, 코드 체크, 리소스 압축 등) 을 포함但不限于, 개발過程中에 필요한 도구, 및 릴리스에 필요한 도구도 모두 워크플로우에 속합니다. 워크플로우를 최적화하는 프로세스는 이러한 스텝을 간소화하고, 지루하고 번잡한 일을 도구에 맡기는 것으로, 우리는 해방되어 더 많은 일을 할 수 있어, 효율을 향상할 수 있습니다
도구를 확장하고 유지하기 쉽게 하기 위해, 구조를 고려해야 합니다. 예를 들어:
.
|____bin
| |____wf.js # 명령줄 입구 (명령줄 지시를 받아, 서브명령에 배포)
|____config.json # 설정 파라미터 (예를 들어 동기화해야 할 패스 glob)
|____gulpfile.js # gulp task 정의
|____index.js # package 입구 (package.main)
|____lib # 서브명령
| |____wf-ftp.js # 자측, 제측
| |____wf-sync.js # 다중 브라우저 동기화
| |____wf-test.js
|____node_modules
| |____...
|____package.json
|____README.md
그 중에서 wf-sync 는 Browser Sync 의 포장으로, 다중 브라우저 동기화 (리프레시 동기화, 스크롤 동기화, 스타일 변화 동기화 등) 를 지원하여, 개발過程中에 매우省心합니다
wf-ftp 는 명령줄 ftp 지원을 제공하며, 업로드 대기 패스 glob 및 원격 패스를 설정 가능. 원격 환경은 비교적 안정적이며, 개발過程中에 PM, UI 와 효과를 확인하는 데 사용. 개발 완료 후 wf ftp -r 로 번들하여 제측
위 구조에서 핵심은 index 와 wf 로, 전자는 초기화를 담당하고, 후자는 루팅에 유사
톱레벨 index.js 는 글로벌 설정의 초기화를 담당하고, 서브명령을 約定하며, 서브명령 실행 방법을 제공
var argv = require('yargs').argv;
var colors = require("colors");
var path = require("path");
var config = require("./config.json");
// 명령줄에서 오색찬란한 것을 출력
colors.setTheme({
warn: 'yellow',
debug: 'blue',
...
});
var wf = {
log: function(str) {
console.log(colors.log(str));
},
...
};
Object.defineProperty(global, 'wf', {
enumerable: true,
writable: false,
Configurable: false,
value: wf
});
wf.config = config;
// 서브명령을 실행 (서브명령의 호출 방법을 約定)
wf.run = function() {
// 当前 명령
var cmd = process.argv[2];
// 실행 패스
var cwd = argv.path || argv.p || process.cwd();
wf.cmd = cmd;
wf.cwd = cwd;
var cmdFile = require("./lib/wf-" + cmd);
// lib 중의 각 모듈이 반드시 run() 메서드를 export 하여 입구로 할 것을 요구
cmdFile.run && cmdFile.run();
};
module.exports = wf;
미들레벨 bin/wf.js 는 루팅 제어를 담당. 다음과 같음:
#!/usr/bin/env node
var wf = require("../index.js");
var _ = require("underscore");
var yargs = require('yargs');
var shell = require("shelljs");
var cmd = process.argv[2];
var cmdList = {
"test": "test",
"ftp": "ftp",
"sync": "sync"
};
if (cmdList[cmd]) {
var cmdMod = require("../lib/wf-" + cmd);
if (cmdMod && cmdMod.name && cmdMod.desc) {
// 서브명령을 설정
var argv = yargs.command(cmdMod.name, cmdMod.desc, function(yargs) {
cmdMod.usage && yargs.usage(cmdMod.usage);
cmdMod.param && _.each(cmdMod.param, function(v, i) {
yargs.option(v.short, {
alias: v.full,
describe: v.describe,
// 필수인지 여부
demand: v.demand
});
});
yargs.help("h").alias("h", "help");
}).argv;
if (argv.h || argv.help) {
yargs.help('h').argv;
return;
}
// 서브명령을 실행
wf.run();
}
} else {
if (yargs.argv.h || yargs.argv.help) {
yargs.usage('Usage: wf [options]')
.example('wf test', '설치가 성공했는지 테스트')
.example('wf ftp', 'ftp 업로드')
.example('wf sync', '다중 브라우저 동기화')
.help('h')
.alias('h', 'help').argv;
} else {
shell.exec("wf -h");
}
}
하층 lib/wf-xxx.js 는 gulpfile.js 에서 정의된 task 의 실행을 담당. 예를 들어 wf-sync.js:
/**
* 다중 브라우저 동기화
*/
var shell = require('shelljs');
var argv = require('yargs').argv;
module.exports = {
run: function() {
var cwd = wf.cwd;
var cmd = wf.cmd;
shell.cd(__dirname + '/../');
shell.exec('gulp sync --cwd=' + cwd);
},
name: 'sync',
desc: "다중 브라우저 동기화",
usage: "Usage: wf sync"
};
바닥층 gulp task 는 일을 담당. 예를 들어 gulpfile.js 중의 sync:
var browserSync = require('browser-sync').create(),
/**
* BrowserSync task.
*
*
* Usage: `gulp sync`
*/
gulp.task('sync', function() {
// browser sync
browserSync.init({
port: 3333,
server: cwd
});
gulp.watch(cwd + '**/*.*').on('change', browserSync.reload);
});
더 아래는 신경 쓰지 않습니다. 돌아서 각 모듈의 작용을 봅니다:
shelljs 명령어 실행을 담당. `require('child_process').spawn(CMD)` 와 유사하지만, 크로스플랫폼 포장 제공
yargs 명령줄 파라미터의 수신 및 전달을 담당. 명령줄->node->gulp task. 더욱이 문서 생성 (명령줄 헬프) 도 담당
colors 錦上添花의 것, 중요하지 않음
gulp 및 n 개의 플러그인 일을 담당
package.json 은 의존, 입구와 실행 가능 파일 위치를 선언. 다음과 같음:
{
"name": "wf",
"version": "1.0.0",
"description": "for better workflow",
"main": "index.js",
"dependencies": {},
"devDependencies": {
"browser-sync": "^2.14.0",
"colors": "^1.1.2",
"gulp": "^3.9.1",
"gulp-rename": "^1.2.2",
"gulp-util": "^3.0.7",
"shelljs": "^0.7.3",
"underscore": "^1.8.3",
"vinyl-ftp": "^0.5.0",
"yargs": "^4.8.1"
},
"bin": {
"wf": "bin/wf.js"
}
}
npm link 로 글로벌에 링크한 후,愉快地:
wf go # 프로젝트 디렉토리 생성
wf sync # Browser Sync 시작, 미친 개발 모드 진입
wf ftp # ftp 개인 디렉토리에 업로드, PM, UI 와 효과 확인
wf ftp -a # 파일 변화 감시, 자동 ftp, 효과가 빈번히 변경될 때 시작
wf ftp -r # 개발 완료, 제측, 번들하여 ftp 공공 디렉토리에 업로드
五.まとめ
워크플로우를 최적화하여 시간 절약 및 효율 향상
grunt 를 사용?gulp?webpack?fis?rollup?npm scripts?어느 것도 중요하지 않음. 사용하기 편한 도구로 일상 작업을 간소화하는 것이 목적
2 시간 투자하여 몇 년 동안回报가 있는 일은, 일찍 할수록 좋음. 게다가, node 는 모든 것을 익숙하고 간단하게 함. 순수 FEer 도分分钟로 사용하기 편한 명령줄 도구를 만들 수 있음
참고 자료
-
내가 왜 Gulp 와 Grunt 를 포기하고 npm scripts 로 갈아탔는가 (중): 이 3 편은 모두 좋음, 객관적으로 받아들임
아직 댓글이 없습니다