본문으로 건너뛰기

gulp 로 5 분만에 워크플로우 최적화

무료2016-08-20#Tool#gulp教程#BrowserSync#多浏览器同步#前端工作流

워크플로우를 최적화하여 시간 절약 및 효율 향상

서문에

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 명령줄 도구를捏造하다

글로벌 명령어를 커스터마이즈하고 싶습니까?어떤 디렉토리에서도 실행 가능?실제로 매우 쉽습니다

  1. nodejs 코드를编写하고, Shebang 추가 (파일 첫 행에 #!/usr/bin/env node 추가, node 로 이 파일을 실행함을 나타냄), xxx.js 로 저장

  2. npm init 또는 직접 package.json 을 손으로 씀

  3. package.json 을修改하고, "bin": {"hoho": "xxx.js"} 추가

  4. 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-syncBrowser Sync 의 포장으로, 다중 브라우저 동기화 (리프레시 동기화, 스크롤 동기화, 스타일 변화 동기화 등) 를 지원하여, 개발過程中에 매우省心합니다

wf-ftp 는 명령줄 ftp 지원을 제공하며, 업로드 대기 패스 glob 및 원격 패스를 설정 가능. 원격 환경은 비교적 안정적이며, 개발過程中에 PM, UI 와 효과를 확인하는 데 사용. 개발 완료 후 wf ftp -r 로 번들하여 제측

위 구조에서 핵심은 indexwf 로, 전자는 초기화를 담당하고, 후자는 루팅에 유사

톱레벨 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.jsgulpfile.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 도分分钟로 사용하기 편한 명령줄 도구를 만들 수 있음

참고 자료

댓글

아직 댓글이 없습니다

댓글 작성