Gulp + Webpack 还是只有 Webpack?

我看到人们使用网络包吞咽。但是后来我读到网络包可以代替吞咽吗?我完全糊涂了,有人能解释一下吗?

更新

最后我一口气喝了下去。我刚接触现代前端,只想快点起来跑。一年多过去了,现在我的脚已经湿透了,我准备转而使用 webpack。我建议穿着同样鞋子出发的人走同样的路线。并不是说你不能尝试 webpack,只是说如果它看起来很复杂的话,先从一大口开始... 没什么不对的。

如果你不想吞咽,是的,这里有 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"
},
71577 次浏览

这个答案可能会有帮助

这里有一个在吞咽任务中使用 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();
}
}
}
}

我想你会发现随着你的应用变得越来越复杂,你可能会像上面的例子一样使用 webpack 任务。这允许您在构建中做一些 webpack 加载程序和插件实际上不能做的有趣的事情,即。创建输出目录、启动服务器等。简而言之,webpack 实际上可以做这些事情,但是您可能会发现它们对于您的长期需求是有限的。Gulp-> webpack 的最大优点之一是,您可以针对不同的环境定制 webpack 配置,并让 Gulp 在正确的时间执行正确的任务。这完全取决于你,但是从 Gulp 运行 webpack 并没有什么错,事实上有一些相当不错的 有意思例子来说明如何做到这一点。上面的例子基本上来自 Jlongster

我在不同的项目中使用了这两个选项。

下面是我用 gulpwebpack-https://github.com/iroy2000/react-reflux-boilerplate-with-webpack组合起来的一个样板。

我有一些其他的项目只使用 webpacknpm tasks

它们都很好用。我认为,归根结底就是你的任务有多复杂,以及你希望在配置中拥有多少控制权。

例如,如果您的任务是简单的,让我们说 devbuildtest... 等(这是非常标准的) ,您完全可以只使用简单的 webpacknpm tasks

但是,如果你有非常复杂的工作流程,你想有更多的控制你的配置(因为它是编码) ,你可以去狼吞虎咽的路线。

但是根据我的经验,webpack 生态系统提供了足够多的插件和加载程序,所以我喜欢使用最低限度的方法,除非有些事情你只能一口气做完。而且,如果您的系统中少了一样东西,它将使您的配置更加容易。

很多时候,现在,我看到人们实际上取代 gulp and browsify一起与 webpack单独。

NPM 脚本 可以执行与 Gulp 相同的操作,但是使用的代码要少50倍。实际上,在没有任何代码的情况下,只有命令行参数。

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

使用 Webpack + NPM 脚本,就这么简单:

"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 脚本很酷,所以它支持简单的链接,类似于 Streams/tube 的 Gulp。

在上面的示例中,要构建用于开发的代码,只需转到命令行并执行 npm run build:dev

  1. NPM 将首先运行 prebuild:dev,
  2. 然后是 build:dev,
  3. 最后是 postbuild:dev

prepost前缀告诉 NPM 执行哪个顺序。

如果您注意到,使用 Webpack + NPM 脚本,您可以运行一个本机程序,比如 rimraf,而不是一个本机程序(比如 gulp-rimraf)的封装器。也可以运行本机 Windows。Exe 文件,就像我在这里用 Linux 或 Mac 上的 elevate.exe或原生 * nix 文件所做的那样。

尝试做同样的事情与吞咽。您必须等待有人来为您想要使用的本机程序编写一个吞咽包装器。此外,您可能需要编写如下复杂的代码: (直接从 有角的2粒种子 repo 获取)

Gulp 开发代码

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));
};

实际的吞噬代码要比这个复杂得多,因为这只是回购文件中几十个吞噬文件中的两个。

那么,哪个对你来说更容易?

在我看来,NPM 脚本在有效性和易用性方面远远超过了吞咽和呼噜,所有的前端开发人员都应该考虑在他们的工作流程中使用它,因为它是一个主要的节省时间的方法。

更新

在我遇到的一个场景中,我希望将 Gulp 与 NPM 脚本和 Webpack 结合使用。

例如,当我需要在 iPad 或 Android 设备上运行 远程调试时,我需要启动额外的服务器。在过去,我将所有的服务器作为独立的进程来运行,从 IntelliJ IDEA (或 Webstorm)内部,使用“复合”运行配置很容易。但是如果我需要停止并重新启动它们,那么关闭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

我现在使用一个名为 同时的脚本,它执行与上面的 Gulp 任务相同的操作。它并行地运行多个 CLI 脚本,并将它们全部传送到同一个控制台窗口,而且使用起来非常简单。同样,不需要任何代码(好吧,代码在 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 脚本可以在没有代码的情况下完成相同的任务。

我建议你读读这些文章,深入比较一下。

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 的混合,这样你和你的团队就不需要学习和维护这两者,特别是因为他们需要非常不同的思维模式。

说实话,我觉得最好是两者都用。

  • Webpack 用于所有与 Javascript相关的。
  • 所有与 CSS相关的。

我仍然需要找到一个像样的解决方案来包装 css 和 webpack,到目前为止,我很高兴使用 Gulp for css 和 webpack for javascript。

我还使用 npm脚本作为@Tetradev,如上所述。特别是因为我使用的是 Visual Studio,而 NPM Task runner是相当 可靠Webpack Task Runner是相当 马车的。