Gulp + Webpack 还是仅使用 Webpack?

168

我看到有人同时使用gulp和webpack。但是我读到webpack可以替代gulp?我完全困惑了……有人能解释一下吗?

更新:

最终,我选择了gulp。当时我对现代前端开发还很陌生,只想快速上手。现在,已经过去了一年多,我已经入门了,准备转向webpack。我建议那些刚开始学习的人也这样做。不是说你不能尝试webpack,但是如果它看起来很复杂,请先从gulp开始,这没有什么不好。

如果你不想用gulp,当然可以使用grunt,但是你也可以在package.json文件中指定命令,并在命令行中调用它们,而无需使用任务运行器,只是为了最初快速上手。例如:

"scripts": {
      "babel": "babel src -d build",
      "browserify": "browserify build/client/app.js -o dist/client/scripts/app.bundle.js",
      "build": "npm run clean && npm run babel && npm run prepare && npm run browserify",
      "clean": "rm -rf build && rm -rf dist",
      "copy:server": "cp build/server.js dist/server.js",
      "copy:index": "cp src/client/index.html dist/client/index.html",
      "copy": "npm run copy:server && npm run copy:index",
      "prepare": "mkdir -p dist/client/scripts/ && npm run copy",
      "start": "node dist/server"
    },

4
这篇文章帮助我更好地理解Webpack,比Webpack官方文档或其他文章都更有效:https://github.com/petehunt/webpack-howto - George Ananda Eman
使用Webpack的时候,为什么不需要再使用Gulp - Andy Ray
我的简单例子是,我想让webpack-dev-server处理我的js并使用HMR,但我遇到了问题,无法同时使用静态站点生成器和webpack dev server。通过复杂的配置可以实现这一点,但是使用简单直接的gulp也可以做到。因此,主要区别在于时间和学习曲线。 - dewwwald
两年过去了,我仍然在类似的问题上挣扎(https://stackoverflow.com/questions/46323410/build-a-pretty-gulp-ish-less-compilation-chain-in-webpack-v3)。 - Frank N
您的更新应该作为答案,+1。 - Bernardo Dal Corno
5个回答

86
这个答案可能有所帮助。任务运行器(Gulp、Grunt等)和捆绑器(Webpack、Browserify)。为什么要一起使用? 以下是在gulp任务中使用webpack的示例。这更进一步假设你的webpack配置是用es6编写的。
var gulp = require('gulp');
var webpack = require('webpack');
var gutil = require('gutil');
var babel = require('babel/register');
var config = require(path.join('../..', 'webpack.config.es6.js'));

gulp.task('webpack-es6-test', function(done){
   webpack(config).run(onBuild(done));
});

function onBuild(done) {
    return function(err, stats) {
        if (err) {
            gutil.log('Error', err);
            if (done) {
                done();
            }
        } else {
            Object.keys(stats.compilation.assets).forEach(function(key) {
                gutil.log('Webpack: output ', gutil.colors.green(key));
            });
            gutil.log('Webpack: ', gutil.colors.blue('finished ', stats.compilation.name));
            if (done) {
                done();
            }
        }
    }
}

我认为随着您的应用程序变得更加复杂,您可能会想要使用gulp与webpack任务,就像上面的示例一样。这使您可以在构建中执行一些更有趣的操作,而webpack加载器和插件实际上无法执行,例如创建输出目录,启动服务器等。当然,webpack实际上也可以执行这些操作,但是您可能会发现对于长期需求来说它们有限制。从gulp到webpack获得的最大优势之一是,您可以为不同的环境自定义webpack配置,并让gulp在正确的时间执行正确的任务。这完全取决于您,但是从gulp运行webpack没有问题,实际上还有一些非常有趣的示例可以参考。上面的示例基本上来自jlongster

我的webpack项目非常大 - 因此我需要通过命令行命令增加节点内存。 https://dev59.com/E5Lea4cB1Zd3GeqP8egS 是否有直接通过webpack进行操作的方法? - Abhinav Singi
看看这两个。在运行node或webpack之前,您可能需要设置v8内存。https://dev59.com/3mw05IYBdhLWcg3wgyHI和https://webpack.github.io/docs/build-performance.html - 4m1r
我不确定为什么我接受了这个答案。我想可能是因为你分享的第一个链接。但是使用gulp从webpack开始?如果你问我,那就更加混乱了:). 我甚至不会尝试诉诸于这样的东西。 - PositiveGuy

81

NPM脚本可以像gulp一样完成相同的功能,但代码量约少了50倍。事实上,只需要使用命令行参数,而不需要任何代码。

例如,您描述的用例是希望在不同的环境中具有不同的代码。

使用Webpack + NPM Scripts,这很容易:

"prebuild:dev": "npm run clean:wwwroot",
"build:dev": "cross-env NODE_ENV=development webpack --config config/webpack.development.js --hot --profile --progress --colors --display-cached",
"postbuild:dev": "npm run copy:index.html && npm run rename:index.html",

"prebuild:production": "npm run clean:wwwroot",
"build:production": "cross-env NODE_ENV=production webpack --config config/webpack.production.js --profile --progress --colors --display-cached --bail",
"postbuild:production": "npm run copy:index.html && npm run rename:index.html",

"clean:wwwroot": "rimraf -- wwwroot/*",
"copy:index.html": "ncp wwwroot/index.html Views/Shared",
"rename:index.html": "cd ../PowerShell && elevate.exe -c renamer --find \"index.html\" --replace \"_Layout.cshtml\" \"../MyProject/Views/Shared/*\"",

现在你只需维护两个webpack配置脚本,一个是开发模式的webpack.development.js,另一个是生产模式的webpack.production.js。我还使用了一个webpack.common.js文件,其中包含所有环境共享的webpack配置,并使用webpackMerge将它们合并。
由于NPM脚本的强大功能,它允许轻松链接,类似于gulp的Streams/pipes。
在上面的示例中,要构建开发版本,只需进入命令行并执行npm run build:dev
  1. NPM首先运行prebuild:dev
  2. 然后运行build:dev
  3. 最后运行postbuild:dev
前缀prepost告诉NPM要执行的顺序。
如果您注意到,在Webpack + NPM脚本中,您可以运行本地程序,例如rimraf,而不是像gulp-rimraf那样使用gulp-wrapper来运行本地程序。您还可以像这里使用elevate.exe一样在Windows上运行原生的.exe文件,或者在Linux或Mac上运行本地*nix文件。
尝试使用gulp做同样的事情。您将需要等待有人编写gulp-wrapper来使用您想要使用的本地程序。此外,您可能需要编写像这样复杂的代码:(直接从angular2-seed存储库中获取)
import * as gulp from 'gulp';
import * as gulpLoadPlugins from 'gulp-load-plugins';
import * as merge from 'merge-stream';
import * as util from 'gulp-util';
import { join/*, sep, relative*/ } from 'path';

import { APP_DEST, APP_SRC, /*PROJECT_ROOT, */TOOLS_DIR, TYPED_COMPILE_INTERVAL } from '../../config';
import { makeTsProject, templateLocals } from '../../utils';

const plugins = <any>gulpLoadPlugins();

let typedBuildCounter = TYPED_COMPILE_INTERVAL; // Always start with the typed build.

/**
 * Executes the build process, transpiling the TypeScript files (except the spec and e2e-spec files) for the development
 * environment.
 */
export = () => {
  let tsProject: any;
  let typings = gulp.src([
    'typings/index.d.ts',
    TOOLS_DIR + '/manual_typings/**/*.d.ts'
  ]);
  let src = [
    join(APP_SRC, '**/*.ts'),
    '!' + join(APP_SRC, '**/*.spec.ts'),
    '!' + join(APP_SRC, '**/*.e2e-spec.ts')
  ];

  let projectFiles = gulp.src(src);
  let result: any;
  let isFullCompile = true;

  // Only do a typed build every X builds, otherwise do a typeless build to speed things up
  if (typedBuildCounter < TYPED_COMPILE_INTERVAL) {
    isFullCompile = false;
    tsProject = makeTsProject({isolatedModules: true});
    projectFiles = projectFiles.pipe(plugins.cached());
    util.log('Performing typeless TypeScript compile.');
  } else {
    tsProject = makeTsProject();
    projectFiles = merge(typings, projectFiles);
  }

  result = projectFiles
    .pipe(plugins.plumber())
    .pipe(plugins.sourcemaps.init())
    .pipe(plugins.typescript(tsProject))
    .on('error', () => {
      typedBuildCounter = TYPED_COMPILE_INTERVAL;
    });

  if (isFullCompile) {
    typedBuildCounter = 0;
  } else {
    typedBuildCounter++;
  }

  return result.js
    .pipe(plugins.sourcemaps.write())
// Use for debugging with Webstorm/IntelliJ
// https://github.com/mgechev/angular2-seed/issues/1220
//    .pipe(plugins.sourcemaps.write('.', {
//      includeContent: false,
//      sourceRoot: (file: any) =>
//        relative(file.path, PROJECT_ROOT + '/' + APP_SRC).replace(sep, '/') + '/' + APP_SRC
//    }))
    .pipe(plugins.template(templateLocals()))
    .pipe(gulp.dest(APP_DEST));
};

Gulp 生产代码

import * as gulp from 'gulp';
import * as gulpLoadPlugins from 'gulp-load-plugins';
import { join } from 'path';

import { TMP_DIR, TOOLS_DIR } from '../../config';
import { makeTsProject, templateLocals } from '../../utils';

const plugins = <any>gulpLoadPlugins();

const INLINE_OPTIONS = {
  base: TMP_DIR,
  useRelativePaths: true,
  removeLineBreaks: true
};

/**
 * Executes the build process, transpiling the TypeScript files for the production environment.
 */

export = () => {
  let tsProject = makeTsProject();
  let src = [
    'typings/index.d.ts',
    TOOLS_DIR + '/manual_typings/**/*.d.ts',
    join(TMP_DIR, '**/*.ts')
  ];
  let result = gulp.src(src)
    .pipe(plugins.plumber())
    .pipe(plugins.inlineNg2Template(INLINE_OPTIONS))
    .pipe(plugins.typescript(tsProject))
    .once('error', function () {
      this.once('finish', () => process.exit(1));
    });


  return result.js
    .pipe(plugins.template(templateLocals()))
    .pipe(gulp.dest(TMP_DIR));
};

实际的gulp代码比这个复杂得多,因为这只是库中数十个gulp文件中的两个。
那么,哪一个对你来说更容易呢?
在我看来,NPM脚本在效率和易用性方面远远超过了gulp和grunt,所有前端开发人员都应该考虑在其工作流程中使用它,因为它可以节省大量时间。
更新
我遇到了一种情况,我想在其中将Gulp与NPM脚本和Webpack结合使用。
例如,当我需要在iPad或Android设备上进行远程调试时,我需要启动额外的服务器。 过去,我将所有服务器作为单独的进程运行,从IntelliJ IDEA(或Webstorm)中很容易使用“Compound”运行配置。 但是,如果我需要停止并重新启动它们,那么关闭5个不同的服务器选项卡非常繁琐,并且输出分散在不同的窗口中。
gulp的好处之一是可以将所有独立进程的输出链接在一起,形成一个控制台窗口,该窗口成为所有子服务器的父级。
因此,我创建了一个非常简单的gulp任务,只需运行我的NPM脚本或直接运行命令,因此所有输出都显示在一个窗口中,我可以通过关闭gulp任务窗口一次结束所有5个服务器。
Gulp.js
/**
 * Gulp / Node utilities
 */
var gulp = require('gulp-help')(require('gulp'));
var utils = require('gulp-util');
var log = utils.log;
var con = utils.colors;

/**
 * Basic workflow plugins
 */
var shell = require('gulp-shell'); // run command line from shell
var browserSync = require('browser-sync');

/**
 * Performance testing plugins
 */
var ngrok = require('ngrok');

// Variables
var serverToProxy1 = "localhost:5000";
var finalPort1 = 8000;


// When the user enters "gulp" on the command line, the default task will automatically be called. This default task below, will run all other tasks automatically.

// Default task
gulp.task('default', function (cb) {
   console.log('Starting dev servers!...');
   gulp.start(
      'devserver:jit',
      'nodemon',
      'browsersync',
      'ios_webkit_debug_proxy'
      'ngrok-url',
      // 'vorlon',
      // 'remotedebug_ios_webkit_adapter'
   );
});

gulp.task('nodemon', shell.task('cd ../backend-nodejs && npm run nodemon'));
gulp.task('devserver:jit', shell.task('npm run devserver:jit'));
gulp.task('ios_webkit_debug_proxy', shell.task('npm run ios-webkit-debug-proxy'));
gulp.task('browsersync', shell.task(`browser-sync start --proxy ${serverToProxy1} --port ${finalPort1} --no-open`));
gulp.task('ngrok-url', function (cb) {
   return ngrok.connect(finalPort1, function (err, url) {
      site = url;
      log(con.cyan('ngrok'), '- serving your site from', con.yellow(site));
      cb();
   });
});
// gulp.task('vorlon', shell.task('vorlon'));
// gulp.task('remotedebug_ios_webkit_adapter', shell.task('remotedebug_ios_webkit_adapter'));

在我看来,为了运行5个任务而编写的代码还是有点多,但这对于目的来说是有效的。一个注意点是,gulp-shell似乎无法正确运行某些命令,比如ios-webkit-debug-proxy。因此,我不得不创建一个只执行相同命令的NPM脚本,然后它就可以正常工作了。

因此,我主要使用NPM脚本来完成所有任务,但偶尔当我需要同时运行一堆服务器时,我会启动我的Gulp任务来帮忙。选择合适的工具来完成合适的工作。

更新2

我现在使用一个叫做concurrently的脚本,它与上面的gulp任务执行相同的功能。它可以并行运行多个CLI脚本,并将它们全部传输到同一个控制台窗口,非常简单易用。再次强调,不需要编写任何代码(好吧,代码在concurrently的node_module中,但您不必关心它)。

// NOTE: If you need to run a command with spaces in it, you need to use 
// double quotes, and they must be escaped (at least on windows).
// It doesn't seem to work with single quotes.

"run:all": "concurrently \"npm run devserver\" nodemon browsersync ios_webkit_debug_proxy ngrok-url"

这个命令可以并行运行所有 5 个脚本,并管道输出到一个终端窗口。很棒!所以在这一点上,我很少使用 gulp,因为有许多 cli 脚本可以完成相同的任务而无需编写代码。

我建议您阅读这些深入比较它们的文章。


16
那是因为你的任务相对简单。祝你在使用shell编写复杂构建脚本时好运 :-) - Filip Sobczak
6
这只是例子。我的构建非常复杂,有许多在 shell 上执行的脚本,运行完美且易于维护。而且,如果 NPM 脚本无法满足我的需求,webpack 将会帮我完成,例如压缩、gzip、转换等等。谢谢。你需要 gulp 做什么才会这么复杂? - TetraDev
2
(超过一年后哈哈):非常感谢,回答得太好了!! - PositiveGuy
1
@user108471 当然可以使用webpack,它可以创建一个assets.json文件,其中列出了所有已编译模块及其关联的ID。使用正确的插件还可以创建许多其他类型的构建时信息JSON文件。您具体指的是gulp可以做哪种类型的文件呢? - TetraDev
1
@GiannosCharalambous 谢谢你的提示。我已经使用 npm-run-all 几个月了,但我甚至没有想到使用 -p 并行标志!我这周会尝试一下。 - TetraDev
显示剩余5条评论

8
我在不同的项目中都使用了这两个选项。
这里是我用 gulpwebpack 搭建的一个样板文件 - https://github.com/iroy2000/react-reflux-boilerplate-with-webpack
我有一些其他项目只使用了 webpacknpm tasks
它们都可以完美地工作。 我认为,这取决于你的任务有多么复杂以及你想要在配置中拥有多少控制权。
例如,如果你的任务很简单,比如说 dev, build, test...等(非常标准),那么只使用简单的 webpacknpm tasks 就足够了。
但是,如果你有非常复杂的工作流程,并且你想要更多地控制你的配置(因为它是编码),那么你可以选择 gulp 路线。
但是根据我的经验,webpack 生态系统提供了足够的插件和加载器,我会需要的所有内容,所以我喜欢使用最基本的方法,除非有些事情只能在 gulp 中完成。此外,如果你的系统中有一项不必要的内容,那么删除它将使你的配置更加简单。
而且很多时候,现在人们实际上是用 webpack 单独替换了 gulp and browsify

5
是的,但Webpack一直以来被认为过于复杂难以理解。我倾向于先尝试使用gulp和browserify,还没有准备好去使用Webpack,部分原因是我在前端方面并没有太多涉猎Browserify或者node,所以我想先学习一下每个人是如何使用gulp和browserify的,这样我就有了那些经验的历史。 - PositiveGuy
1
Webpack只有在你没有使用过它时才会变得复杂,就像gulp、grunt、browserify、typescript和其他任何东西一样。一旦你理解了如何设置配置文件并使用加载器,Webpack就非常容易使用。实际上,对于一个工作的Webpack构建,配置文件可以只有20-30行代码,并且可以像你需要的那样强大。更不用说Webpack热模块替换功能是绝对惊人的。请参见:http://andrewhfarmer.com/understanding-hmr/ 和 http://andrewhfarmer.com/webpack-hmr-tutorial/ 和 https://medium.com/@dabit3/beginner-s-guide-to-webpack-b1f1a3638460 - TetraDev

2
Gulp和Webpack的概念是非常不同的。通过逐步告诉Gulp如何将前端代码组合在一起,但是通过配置文件告诉Webpack您想要什么。
这里是我写的一篇简短的文章(5分钟读取时间),解释了我对差异的理解:https://medium.com/@Maokai/compile-the-front-end-from-gulp-to-webpack-c45671ad87fe 我们公司在过去一年中从Gulp转移到Webpack。虽然花费了一些时间,但我们找到了如何将我们在Gulp中所做的所有工作移动到Webpack的方法。因此,对于我们来说,在Gulp中所做的所有事情,我们也可以通过Webpack完成,但反之则不行。
截至今天,我建议只使用Webpack,避免混合使用Gulp和Webpack,以便您和您的团队不需要学习和维护两者,特别是因为它们需要非常不同的思维方式。

2

老实说,我认为最好同时使用两者。

  • Webpack 用于所有与javascript相关的内容。
  • Gulp 用于所有与css相关的内容。

我仍然需要找到一个合适的解决方案来使用webpack打包css,到目前为止,我很满意使用gulp处理css和webpack处理javascript。

我还使用npm脚本,就像@Tetradev所描述的那样。特别是因为我正在使用Visual Studio,而且虽然NPM任务运行器非常可靠,但Webpack任务运行器相当有问题。


我发现使用NPM任务运行器+Gulp是关键。将webpack命令放入packange.json文件中,将CSS(SASS)相关内容放入gulp文件中。还要设置package.json以具有构建步骤,该步骤作为生产发布的一部分调用gulp任务。 - Nico
你已经完全转向webpack了吗?我也有同样的问题。它的CSS处理方式非常奇怪。整个webpack似乎都围绕着它展开,所以其他所有东西都只是额外的。我只想像往常一样构建我的CSS,并将它们放在我想要的文件夹中(与JS分开)。使用webpack似乎非常复杂。现在我只能用gulp来完成这个简单的任务。 - mr1031011
@mr1031011 这些天我正在使用NetCore捆绑和压缩编译CSS https://learn.microsoft.com/en-us/aspnet/core/client-side/bundling-and-minification?view=aspnetcore-3.1 - Max Favilli

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