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
。
- NPM首先运行
prebuild:dev
,
- 然后运行
build:dev
,
- 最后运行
postbuild:dev
。
前缀
pre
和
post
告诉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 } from 'path';
import { APP_DEST, APP_SRC, TOOLS_DIR, TYPED_COMPILE_INTERVAL } from '../../config';
import { makeTsProject, templateLocals } from '../../utils';
const plugins = <any>gulpLoadPlugins();
let typedBuildCounter = TYPED_COMPILE_INTERVAL;
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;
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())
.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
};
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
var gulp = require('gulp-help')(require('gulp'));
var utils = require('gulp-util');
var log = utils.log;
var con = utils.colors;
var shell = require('gulp-shell');
var browserSync = require('browser-sync');
var ngrok = require('ngrok');
var serverToProxy1 = "localhost:5000";
var finalPort1 = 8000;
gulp.task('default', function (cb) {
console.log('Starting dev servers!...');
gulp.start(
'devserver:jit',
'nodemon',
'browsersync',
'ios_webkit_debug_proxy'
'ngrok-url',
);
});
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();
});
});
在我看来,为了运行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 脚本可以完成相同的任务而无需编写代码。
我建议您阅读这些深入比较它们的文章。