使用Gulp拼接和压缩文件

128

我正在尝试使用Gulp来完成以下任务:

  1. 将3个特定的JavaScript文件进行连接,然后将结果保存到一个文件中(concat.js)
  2. 对这个连接后的文件进行压缩和混淆(minify/uglify),然后将结果保存到另一个文件中(uglify.js)

目前我已经有了以下代码:

    var gulp = require('gulp'),
        gp_concat = require('gulp-concat'),
        gp_uglify = require('gulp-uglify');

    gulp.task('js-fef', function(){
        return gulp.src(['file1.js', 'file2.js', 'file3.js'])
            .pipe(gp_concat('concat.js'))
            .pipe(gp_uglify())
            .pipe(gulp.dest('js'));
    });

    gulp.task('default', ['js-fef'], function(){});

然而,uglify操作似乎没有起作用,或者由于某些原因文件没有生成。

我需要做什么才能让它发生?


3
惊讶地没有看到它,所以我想快速说一下,这个目标本身有些违背了Gulp的哲学。编写中间文件更多是Grunt的工作方式。Gulp推崇使用流来提高速度。但我相信询问的人有他的理由 :)。 - Bart
我知道这是一个旧的帖子,但是我已经制作了一个npm模块,可以使用yaml文件来轻松完成这种工作。查看:http://github.com/Stnaire/gulp-yaml-packages。 - Stnaire
6个回答

166

事实证明我需要使用 gulp-rename 插件并在“代码压缩”之前先输出合并的文件。以下是代码:

gulp.src('src/js/*.js') .pipe(concat('all.js')) .pipe(gulp.dest('dist/js')) .pipe(rename('all.min.js')) .pipe(uglify()) .pipe(gulp.dest('dist/js'));
var gulp = require('gulp'),
    gp_concat = require('gulp-concat'),
    gp_rename = require('gulp-rename'),
    gp_uglify = require('gulp-uglify');

gulp.task('js-fef', function(){
    return gulp.src(['file1.js', 'file2.js', 'file3.js'])
        .pipe(gp_concat('concat.js'))
        .pipe(gulp.dest('dist'))
        .pipe(gp_rename('uglify.js'))
        .pipe(gp_uglify())
        .pipe(gulp.dest('dist'));
});

gulp.task('default', ['js-fef'], function(){});

一开始从 grunt 转过来有点困惑,不过现在明白了。希望能对新手学习 gulp 有所帮助。

另外,如果需要源映射,请使用以下更新后的代码:

var gulp = require('gulp'),
    gp_concat = require('gulp-concat'),
    gp_rename = require('gulp-rename'),
    gp_uglify = require('gulp-uglify'),
    gp_sourcemaps = require('gulp-sourcemaps');

gulp.task('js-fef', function(){
    return gulp.src(['file1.js', 'file2.js', 'file3.js'])
        .pipe(gp_sourcemaps.init())
        .pipe(gp_concat('concat.js'))
        .pipe(gulp.dest('dist'))
        .pipe(gp_rename('uglify.js'))
        .pipe(gp_uglify())
        .pipe(gp_sourcemaps.write('./'))
        .pipe(gulp.dest('dist'));
});

gulp.task('default', ['js-fef'], function(){});

有关选项和配置的更多信息,请参阅gulp-sourcemaps

更新 - 2022年2月

如今,使用Gulp4和Async / Await功能处理构建任务可能会更容易:

// gulpfile.js

const fs = require('fs/promises');
const concat = require('concat');
const uglify = require('uglify-js');

let files_arr = ['file1.js', 'file2.js', 'file3.js'];

async function myGulpTask()
{
    var concat_str,
        uglify_str
    ;

    // concat content
    concat_str = await concat(files_arr);

    // save to file
    await fs.writeFile('concat.js', concat_str, 'utf8');

    // uglify content
    uglify_str = await uglify.minify(concat_str, {mangle:false}).code;

    // save to file
    await fs.writeFile('uglify.js', uglify_str, 'utf8');
}

module.exports = {
    myTask: myGulpTask
};

然后从命令行界面执行:

gulp myTask

你漏掉了一个单引号在concat.js之前。在gulp.task中return语句后面的一行应该是:.pipe(gp_concat('concat.js')) - Eric Jorgensen
1
所有文件都已生成,但在调试器中仍然看到被压缩的版本。可能的原因是什么?映射文件命名正确且可以通过其URL访问。 - Meglio
这取决于原始源在不同选项卡上的浏览器。您需要在那里设置断点。 - przemcio
4
我不太清楚为什么我们需要重命名?这是一个错误还是...? - przemcio
在我的情况下,我想要在每个步骤中记录所有文件的记录。然而,如果你只关心最终的压缩文件,那么你当然可以进一步缩短gulp文件。 - ObiHill
显示剩余2条评论

18

我的gulp文件生成了一个最终的compiled-bundle-min.js文件,希望这能帮到某些人。

在此输入图片描述

//Gulpfile.js

var gulp = require("gulp");
var watch = require("gulp-watch");

var concat = require("gulp-concat");
var rename = require("gulp-rename");
var uglify = require("gulp-uglify");
var del = require("del");
var minifyCSS = require("gulp-minify-css");
var copy = require("gulp-copy");
var bower = require("gulp-bower");
var sourcemaps = require("gulp-sourcemaps");

var path = {
    src: "bower_components/",
    lib: "lib/"
}

var config = {
    jquerysrc: [
        path.src + "jquery/dist/jquery.js",
        path.src + "jquery-validation/dist/jquery.validate.js",
        path.src + "jquery-validation/dist/jquery.validate.unobtrusive.js"
    ],
    jquerybundle: path.lib + "jquery-bundle.js",
    ngsrc: [
        path.src + "angular/angular.js",
         path.src + "angular-route/angular-route.js",
         path.src + "angular-resource/angular-resource.js"
    ],
    ngbundle: path.lib + "ng-bundle.js",

    //JavaScript files that will be combined into a Bootstrap bundle
    bootstrapsrc: [
        path.src + "bootstrap/dist/js/bootstrap.js"
    ],
    bootstrapbundle: path.lib + "bootstrap-bundle.js"
}

// Synchronously delete the output script file(s)
gulp.task("clean-scripts", function (cb) {
    del(["lib","dist"], cb);
});

//Create a jquery bundled file
gulp.task("jquery-bundle", ["clean-scripts", "bower-restore"], function () {
    return gulp.src(config.jquerysrc)
     .pipe(concat("jquery-bundle.js"))
     .pipe(gulp.dest("lib"));
});

//Create a angular bundled file
gulp.task("ng-bundle", ["clean-scripts", "bower-restore"], function () {
    return gulp.src(config.ngsrc)
     .pipe(concat("ng-bundle.js"))
     .pipe(gulp.dest("lib"));
});

//Create a bootstrap bundled file
gulp.task("bootstrap-bundle", ["clean-scripts", "bower-restore"], function     () {
    return gulp.src(config.bootstrapsrc)
     .pipe(concat("bootstrap-bundle.js"))
     .pipe(gulp.dest("lib"));
});


// Combine and the vendor files from bower into bundles (output to the Scripts folder)
gulp.task("bundle-scripts", ["jquery-bundle", "ng-bundle", "bootstrap-bundle"], function () {

});

//Restore all bower packages
gulp.task("bower-restore", function () {
    return bower();
});

//build lib scripts
gulp.task("compile-lib", ["bundle-scripts"], function () {
    return gulp.src("lib/*.js")
        .pipe(sourcemaps.init())
        .pipe(concat("compiled-bundle.js"))
        .pipe(gulp.dest("dist"))
        .pipe(rename("compiled-bundle.min.js"))
        .pipe(uglify())
        .pipe(sourcemaps.write("./"))
        .pipe(gulp.dest("dist"));
});

1
很棒的示例@wchoward,正是我所需要的,非常干净简洁的设计。 - Faito

10

使用 gulp-uglifygulp-concatgulp-sourcemaps 解决方案。这来自我正在工作的项目。

gulp.task('scripts', function () {
    return gulp.src(scripts, {base: '.'})
        .pipe(plumber(plumberOptions))
        .pipe(sourcemaps.init({
            loadMaps: false,
            debug: debug,
        }))
        .pipe(gulpif(debug, wrapper({
            header: fileHeader,
        })))
        .pipe(concat('all_the_things.js', {
            newLine:'\n;' // the newline is needed in case the file ends with a line comment, the semi-colon is needed if the last statement wasn't terminated
        }))
        .pipe(uglify({
            output: { // http://lisperator.net/uglifyjs/codegen
                beautify: debug,
                comments: debug ? true : /^!|\b(copyright|license)\b|@(preserve|license|cc_on)\b/i,
            },
            compress: { // http://lisperator.net/uglifyjs/compress, http://davidwalsh.name/compress-uglify
                sequences: !debug,
                booleans: !debug,
                conditionals: !debug,
                hoist_funs: false,
                hoist_vars: debug,
                warnings: debug,
            },
            mangle: !debug,
            outSourceMap: true,
            basePath: 'www',
            sourceRoot: '/'
        }))
        .pipe(sourcemaps.write('.', {
            includeContent: true,
            sourceRoot: '/',
        }))
        .pipe(plumber.stop())
        .pipe(gulp.dest('www/js'))
});

这将合并并压缩所有你的脚本,并将它们放入一个名为all_the_things.js的文件中。该文件将以一行特殊字符结尾。
//# sourceMappingURL=all_the_things.js.map

这告诉您的浏览器查找该地图文件,并将其写出。


8
var gulp = require('gulp');
var concat = require('gulp-concat');
var uglify = require('gulp-uglify');

gulp.task('create-vendor', function () {
var files = [
    'bower_components/q/q.js',
    'bower_components/moment/min/moment-with-locales.min.js',
    'node_modules/jstorage/jstorage.min.js'
];

return gulp.src(files)
    .pipe(concat('vendor.js'))
    .pipe(gulp.dest('scripts'))
    .pipe(uglify())
    .pipe(gulp.dest('scripts'));
});

您的解决方案不起作用,因为您需要在连接过程后保存文件,然后进行压缩并再次保存。在连接和压缩之间无需重命名文件。


我认为决定在使用gulp时需要什么和不需要什么是开发者的特权。在我的情况下,我想在每个步骤中重命名文件。其他人可能有不同的偏好。 - ObiHill
1
当然,你可以决定什么是最好的选择。我理解下面的答案说你需要重命名文件,但我只是说你不需要(这不是必须的),如果我造成了一些混淆,对不起。 - Milos

4

2015年6月10日: gulp-uglifyjs 的作者发表声明:

已废弃: 这个插件因为使用 Uglify 来合并文件而不是使用 gulp-concat,打破了“它应该只做一件事”的原则,因此被列入黑名单。当我创建这个插件时,无法通过 gulp 获取源映射,但现在有一个 gulp-sourcemaps 插件可以实现相同的目标。gulp-uglifyjs 仍然非常好用,并且可以对 Uglify 执行进行非常精细的控制,我只是提醒您现在有其他选项可供选择。


2015年2月18日: 现在 gulp-uglifygulp-concat 都可以很好地与 gulp-sourcemaps 配合使用了。只需正确设置 gulp-concatnewLine 选项即可;我建议使用 \n;


原始回答(2014年12月): 使用 gulp-uglifyjs 替代。 gulp-concat 不一定安全;它需要正确处理尾随分号。 gulp-uglify 也不支持源映射。以下是我正在处理的一个项目的代码片段:

gulp.task('scripts', function () {
    gulp.src(scripts)
        .pipe(plumber())
        .pipe(uglify('all_the_things.js',{
            output: {
                beautify: false
            },
            outSourceMap: true,
            basePath: 'www',
            sourceRoot: '/'
        }))
        .pipe(plumber.stop())
        .pipe(gulp.dest('www/js'))
});

1
@MisterOh 不确定在写作时是否有这个功能,或者如果有的话,可能 gulp-concat 没有(gulp-uglify 不允许您缩小多个文件,因此您必须先进行连接)。此外,默认情况下,gulp-concat 使用 \r\n,如果您的 JS 文件没有正确终止,可能会导致问题。但是,现在有了支持,最好采用这种方法,因为它更灵活。 - mpen
@NightOwl888 好的 实际上,这并不会生成内联的源映射,如果你是在问这个的话;它仍然是一个单独的文件。 - mpen
gulp-uglifyjs现在也已经过时了。现在仅使用gulp-uglify插件就足够了。请查看其他答案以获取最新的解决方案。 - Neil Monroe
@NeilMonroe 谢谢。我在我的答案中添加了一条注释,以使其更清晰。将其保留在这里作为历史记录。 - mpen
@Mark 我不明白。首先,我的问题没有提到 gulp-uglifyjs。最后,你说 gulp-uglifyjs 已经被弃用了,要使用 gulp-uglify 代替?! - ObiHill
显示剩余3条评论

0

我们正在使用以下配置来实现类似的功能

    var gulp = require('gulp'),
    async = require("async"),
    less = require('gulp-less'),
    minifyCSS = require('gulp-minify-css'),
    uglify = require('gulp-uglify'),
    concat = require('gulp-concat'),
    gulpDS = require("./gulpDS"),
    del = require('del');

// CSS & Less
var jsarr = [gulpDS.jsbundle.mobile, gulpDS.jsbundle.desktop, gulpDS.jsbundle.common];
var cssarr = [gulpDS.cssbundle];

var generateJS = function() {

    jsarr.forEach(function(gulpDSObject) {
        async.map(Object.keys(gulpDSObject), function(key) {
            var val = gulpDSObject[key]
            execGulp(val, key);
        });

    })
}

var generateCSS = function() {
    cssarr.forEach(function(gulpDSObject) {
        async.map(Object.keys(gulpDSObject), function(key) {
            var val = gulpDSObject[key];
            execCSSGulp(val, key);
        })
    })
}

var execGulp = function(arrayOfItems, dest) {
    var destSplit = dest.split("/");
    var file = destSplit.pop();
    del.sync([dest])
    gulp.src(arrayOfItems)
        .pipe(concat(file))
        .pipe(uglify())
        .pipe(gulp.dest(destSplit.join("/")));
}

var execCSSGulp = function(arrayOfItems, dest) {
    var destSplit = dest.split("/");
    var file = destSplit.pop();
    del.sync([dest])
    gulp.src(arrayOfItems)
        .pipe(less())
        .pipe(concat(file))
        .pipe(minifyCSS())
        .pipe(gulp.dest(destSplit.join("/")));
}

gulp.task('css', generateCSS);
gulp.task('js', generateJS);

gulp.task('default', ['css', 'js']);

下面是示例GulpDS文件:

{

    jsbundle: {
        "mobile": {
            "public/javascripts/sample.min.js": ["public/javascripts/a.js", "public/javascripts/mobile/b.js"]
           },
        "desktop": {
            'public/javascripts/sample1.js': ["public/javascripts/c.js", "public/javascripts/d.js"]},
        "common": {
            'public/javascripts/responsive/sample2.js': ['public/javascripts/n.js']
           }
    },
    cssbundle: {
        "public/stylesheets/a.css": "public/stylesheets/less/a.less",
        }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接