gulp排除已壓縮文件思路

gulp默認排除語法的弊端

有個時候咱們須要時用gulp排除已經壓縮過的js,css等。若是以壓縮文件是以".min.js"之類命名規範的還好,若是不是呢?並且還有其餘一些場景也會有須要。
gulp默認支持glob格式,排除語法爲!
舉幾個例子:
排除目錄css

gulp.src([
    baseDir + '/**',                              // Include all
    '!' + baseDir + '/excl1{,/**}',               // Exclude excl1 dir
    '!' + baseDir + '/excl2/**/!(.gitignore)',    // Exclude excl2 dir, except .gitignore
], { dot: true });

排除文件:html

gulp.src(['css/**/!(ignore.css)*.css'])
gulp.src([
      '!css/ignnore.css',
      'css/*.css'
    ])

這確實可以排除一些文件。可是還不算強大,不能知足一些複雜的場景。
並且還存在這樣一個問題:當我有一個jquery.min.js,在壓縮js時,我不想對它進行壓縮,但同時我又想將其輸出到dist目錄下。單純採用上面這種方式須要"曲線救國",場景以下:node

gulp.task('jsmin', function (cb) {
        return gulp.src([SRC_DIR+'/**/*.js',,'!'+SRC_DIR+'/**/*.min.js'])
        .pipe(sourcemaps.init())
        .pipe(uglify({mangle: {except: ['require' ,'exports' ,'module' ,'$']}})) //排除混淆關鍵字
        .pipe(sourcemaps.write('.'))
        .pipe(gulp.dest(DEST_DIR));

});

很遺憾地告訴你,*.min.js並無被拷貝到DEST_DIR,固然曲線救國能夠以下:jquery

gulp.task('copy', () =>{
    return gulp.src([SRC_DIR+'/**/*.min.js'])
        .pipe(gulp.dest(DEST_DIR));
    }
);

可是,這不是很優雅。並且上面咱們也說了只是採用glob語法對文件進行排除不適用於複雜的場景。git

Vinyl文件系統

詳細說明,請參考探究Gulp的Stream
如今這裏貼出,後面會說明其目的。
雖然Gulp使用的是Stream,但卻不是普通的Node Stream,實際上,Gulp(以及Gulp插件)用的應該叫作Vinyl File Object Stream。
這裏的Vinyl,是一種虛擬文件格式。Vinyl主要用兩個屬性來描述文件,它們分別是路徑(path)及內容(contents)。具體來講,Vinyl並不神祕,它仍然是JavaScript Object。Vinyl官方給了這樣的示例:github

var File = require('vinyl');
var coffeeFile = new File({
  cwd: "/",
  base: "/test/",
  path: "/test/file.coffee",
  contents: new Buffer("test = 123")
});

從這段代碼能夠看出,Vinyl是Object,path和contents也正是這個Object的屬性。正則表達式

解決方案描述:

能夠採用gulp插件來實現更爲強大的排除。主要有如下幾個插件:
gulp-ignore,支持經過boolean,stat對象,函數來判斷是否排除與包含。判斷函數接受一個Vinyl文件對象,返回一個boolean值。
gulp-filter,支持glob模式、函數過濾,以及過濾後恢復
gulp-if,支持條件判斷(支持函數條件)來控制相關流程。
下面具體說明如何使用gulp

gulp-ignore:

API
exclude(condition [, minimatchOptions])
Exclude files whose file.path matches, include everything else
include(condition [, minimatchOptions])
Include files whose file.path matches, exclude everything else
參數說明:
condition:類型能夠爲 boolean or stat object or function
當爲函數是接受一個vinyl file返回boolean值segmentfault

下面貼出官方例子:api

var gulpIgnore = require('gulp-ignore');
var uglify = require('gulp-uglify');
var jshint = require('gulp-jshint');

var condition = './gulpfile.js';

gulp.task('task', function() {
  gulp.src('./**/*.js')
    .pipe(jshint())
    .pipe(gulpIgnore.exclude(condition))
    .pipe(uglify())
    .pipe(gulp.dest('./dist/'));
});
var gulpIgnore = require('gulp-ignore');
var uglify = require('gulp-uglify');
var jshint = require('gulp-jshint');

var condition = './public/**.js';

gulp.task('task', function() {
  gulp.src('./**/*.js')
    .pipe(jshint())
    .pipe(gulpIgnore.include(condition))
    .pipe(uglify())
    .pipe(gulp.dest('./dist/'));
});

實現:

var condition = function(f){
    if(f.path.endswith('.min.js')){
        return true;
    }
    return false
};

gulp.task('jsmin', function (cb) {
        return gulp.src([SRC_DIR+'/**/*.js'])
        .pipe(gulpIgnore.exclude(condition))
        .pipe(sourcemaps.init())
        .pipe(uglify({mangle: {except: ['require' ,'exports' ,'module' ,'$']}})) //排除混淆關鍵字
        .pipe(sourcemaps.write('.'))
        .pipe(gulp.dest(DEST_DIR));

});

優勢:很明顯,你能夠在條件函數中作你想作的任何事情,包括使用正則表達式等。
缺點:和默認狀況同樣,不支持被排除文件的拷貝

gulp-if

和gulp-ignore做者是同一我的
API:
gulpif(condition, stream [, elseStream, [, minimatchOptions]])
gulp-if will pipe data to stream whenever condition is truthy.
If condition is falsey and elseStream is passed, data will pipe to elseStream
這就相似於三目運算符,功能用僞代碼表示就是if condition then stream(data) else elseStream(data)
After data is piped to stream or elseStream or neither, data is piped down-stream.

參數說明:
condition 與gulp-ignore一致。
Type: boolean or stat object or function that takes in a vinyl file and returns a boolean or RegularExpression that works on the file.path

stream
Stream for gulp-if to pipe data into when condition is truthy.

elseStream
Optional, Stream for gulp-if to pipe data into when condition is falsey.

minimatchOptions
Optional, if it's a glob condition, these options are passed to minimatch.

官方例子:

var gulpif = require('gulp-if');
var uglify = require('gulp-uglify');

var condition = true; // TODO: add business logic

gulp.task('task', function() {
  gulp.src('./src/*.js')
    .pipe(gulpif(condition, uglify()))
    .pipe(gulp.dest('./dist/'));
});

Only uglify the content if the condition is true, but send all the files to the dist folder
僅壓縮符合條件的文件,丹斯全部文件(包括不符合條件的)都會被髮送到dist目錄。

實現:

var condition = function(f){
    if(f.path.endswith('.min.js')){
        return false;
    }
    return true;
};

gulp.task('jsmin', function (cb) {
        return gulp.src([SRC_DIR+'/**/*.js'])
        .pipe(sourcemaps.init())
        .pipe(gulpif(condition, uglify({mangle: {except: ['require' ,'exports' ,'module' ,'$']}}))) //排除混淆關鍵字
        .pipe(sourcemaps.write('.'))
        .pipe(gulp.dest(DEST_DIR));

});

gulp-filter

API
filter(pattern, [options])
Returns a transform stream with a .restore object.
參數說明:
pattern
Type: string, array, function
Accepts a string/array with globbing patterns which are run through multimatch.
若是是函數,則應該接受一個 vinyl file object做爲第一個參數,return true/false whether to include the file:

filter(file => /unicorns/.test(file.path));

選項options
Type: object
Accepts minimatch options.
Note: Set dot: true if you need to match files prefixed with a dot (eg. .gitignore).

options.restore
Type: boolean
Default: false
Restore filtered files.

options.passthrough
Type: boolean
Default: true

When set to true filtered files are restored with a PassThrough stream, otherwise, when set to false, filtered files are restored as a Readable stream.

官方例子:

const gulp = require('gulp');
const uglify = require('gulp-uglify');
const filter = require('gulp-filter');

gulp.task('default', () => {
    // create filter instance inside task function
    const f = filter(['**', '!*src/vendor'], {restore: true});

    return gulp.src('src/**/*.js')
        // filter a subset of the files
        .pipe(f)
        // run them through a plugin
        .pipe(uglify())
        // bring back the previously filtered out files (optional)
        .pipe(f.restore)
        .pipe(gulp.dest('dist'));
});
gulp.task('defaultmulti', () => {
    const jsFilter = filter('**/*.js', {restore: true});
    const lessFilter = filter('**/*.less', {restore: true});

    return gulp.src('assets/**')
        .pipe(jsFilter)
        .pipe(concat('bundle.js'))
        .pipe(jsFilter.restore)
        .pipe(lessFilter)
        .pipe(less())
        .pipe(lessFilter.restore)
        .pipe(gulp.dest('out/'));
});

實戰:

var condition = function(f){
        if(f.path.endswith('.min.js')){
            return false;
        }
        return true;
    };
const jsFilter = filter(condition, {restore: true});
   
    gulp.task('jsmin', function (cb) {
            return gulp.src([SRC_DIR+'/**/*.js'])
            .pipe(jsFilter)
            .pipe(sourcemaps.init())
            .pipe(uglify({mangle: {except: ['require' ,'exports' ,'module' ,'$']}})) //排除混淆關鍵字
            .pipe(sourcemaps.write('.'))
            .pipe(jsFilter.restore)
            .pipe(gulp.dest(DEST_DIR));
    
    });

部分文件被壓縮,全部文件都會被髮送到DEST_DIR

小結

如何選擇?gulp-if:能夠完美解決問題,且足夠優雅。gulp-filter:能夠完美解決問題,可是相比gulp-if略顯麻煩。更復雜的場景下用gulp-filter比gulp-if方便。gulp-ignore:更爲強大的過濾,在僅僅只是過濾而不拷貝的狀況下首推。

相關文章
相關標籤/搜索