Gulp + Webpack还是JUST Webpack?
我看到人们用webpack使用gulp。 但后来我读webpack可以取代吞咽? 我在这里完全困惑…可以解释一下吗?
UPDATE
最后我开始大口喝水。 我是现代前端的新手,只是想快点起床跑步。 现在我已经有一年多的时间了,我已经准备好转移到webpack了。 我build议同样的路线开始在同一个鞋子的人。 不是说你不能尝试webpack,但只是说,如果看起来复杂,从一开始就大口喝…没有什么错。
如果你不想吞下去,是的,但是你也可以在你的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" },
这个答案可能有帮助。 任务跑步者(吞食,咕噜等)和打包者(Webpack,Browserify)。 为什么一起使用?
…这里是一个使用webpack从一个gulp任务的例子。 这更进一步,并假设你的webpackconfiguration是用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任务的gulp。 这允许你在你的构build中做一些更有趣的事情,webpack加载器和插件真的不这样做,即。 创build输出目录,启动服务器等等。简单地说,webpack实际上可以做这些事情,但是你可能会发现它们对你的长期需求是有限的。 从gulp – > webpack获得的最大好处之一就是你可以为不同的环境定制你的webpackconfiguration,并在适当的时候做出正确的select。 它真的取决于你,但是运行webpack从gulp没有什么问题,事实上有一些非常有趣的例子来说明如何去做。 上面的例子基本上来自jlongster 。
NPM脚本可以像吞噬一样做,但是代码less了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/*\"",
现在,您只需维护两个webpackconfiguration脚本,一个用于开发模式, webpack.development.js
,另一个用于生产模式webpack.production.js
。 我还利用一个webpack.common.js
,其中包含在所有环境中共享的webpackconfiguration,并使用webpackMerge来合并它们。
由于NPM脚本的酷炫,它允许简单的链接,类似于gulp如何处理Streams / pipes。
在上面的例子中,为了进行开发,只需转到命令行并执行npm run build:dev
。
- NPM将首先运行
prebuild:dev
, - 然后
build:dev
, - 最后
postbuild:dev
。
pre
和post
前缀告诉NPM执行的顺序。
如果您注意到,使用Webpack + NPM脚本,您可以运行本地程序(如rimraf
,而不是本地程序(如gulp-rimraf
。 您也可以运行本机Windows .exe文件,就像我在这里使用elevate.exe
或Linux或Mac上的本机* nix文件一样。
尝试用吞咽做同样的事情。 你将不得不等待某个人来为你想使用的本地程序写一个gulp-wrapper。 另外,你可能需要写如下这样复杂的代码:(直接从angular2-seed回购)
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)); };
实际的代码代码要复杂得多,因为这只是repo中几十个gulp文件中的两个。
那么,哪一个更容易?
在我看来,NPM脚本在效率和易用性方面远远超过了吞咽和咕</s>,所有的前端开发者都应该考虑在他们的工作stream程中使用它,因为它是一个重要的节省时间。
UPDATE
我遇到过一个场景,我想将Gulp与NPM脚本和Webpack结合使用。
当我需要在iPad或Android设备上进行远程debugging时,我需要启动额外的服务器。 在过去,我将所有的服务器作为单独的进程运行,在IntelliJ IDEA(或Webstorm)中,使用“Compound”运行configuration很容易。 但是,如果我需要停止并重新启动它们,那么必须closures5个不同的服务器选项卡是非常繁琐的,而且输出分布在不同的窗口中。
gulp的好处之一是可以将来自独立独立进程的所有输出链接到一个控制台窗口中,该控制台窗口将成为所有子级服务器的父级。
因此,我创build了一个非常简单的吞咽任务,它只是直接运行我的NPM脚本或命令,所有的输出都出现在一个窗口中,通过closures吞咽任务窗口,我可以轻松地结束所有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
。 所以我不得不创build一个只执行相同的命令的NPM脚本,然后它工作。
所以我主要使用NPM脚本来处理所有的任务,但偶尔当我需要一次运行一堆服务器的时候,我会启动我的Gulp任务来帮忙。 为正确的工作select正确的工具。
我build议你阅读这些比较深入的文章。
- 如何使用NPM作为构build工具
- 为什么我们应该停止使用Grunt&Gulp
- 为什么我为了NPM脚本而G and不安?
我在不同的项目中使用了这两个选项。
这里是一个样板,我用webpack
与webpack
放在一起 – https://github.com/iroy2000/react-reflux-boilerplate-with-webpack 。
我有一些其他项目只使用webpack
npm tasks
。
而且他们都很好。 而且我认为这是你的任务是多么复杂,你想在你的configuration中有多less控制。
例如,如果你的任务很简单,比如说dev
, build
, test
… etc(这是非常标准的),那么用简单的webpack
和npm tasks
你就完全正确了。
但是,如果你有非常复杂的工作stream程,并且你想对你的configuration有更多的控制(因为它是编码),你可以去喝一杯。
但是根据我的经验,webpack生态系统提供了足够多的插件和装载程序,所以我喜欢用最低限度的方法,除非有一些东西只能用于吞咽。 而且,如果你的系统中只有一个东西,它将使你的configuration更容易。
现在很多时候,我发现人们实际上gulp and browsify
用webpack
来取代gulp and browsify
。