Os scripts do NPM podem fazer o mesmo que o gulp, mas com cerca de 50x menos código. De fato, sem nenhum código, apenas argumentos de linha de comando.
Por exemplo, o caso de uso que você descreveu onde deseja ter código diferente para diferentes ambientes.
Com os scripts Webpack + NPM, é fácil:
"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/*\"",
Agora você simplesmente mantém dois scripts de configuração do webpack, um para o modo de desenvolvimento webpack.development.js
e outro para o modo de produção webpack.production.js
. Também utilizo um webpack.common.js
que hospeda a configuração do webpack compartilhada em todos os ambientes e uso o webpackMerge para mesclá-los.
Devido à frescura dos scripts do NPM, ele permite um encadeamento fácil, semelhante ao modo como o Gulp faz o Streams / pipes.
No exemplo acima, para construir para o desenvolvimento, basta acessar a linha de comando e executar npm run build:dev
.
- NPM seria executado primeiro
prebuild:dev
,
- então
build:dev
,
- E, finalmente
postbuild:dev
.
Os prefixos pre
e post
informam ao NPM em que ordem executar.
Se você observar, com os scripts Webpack + NPM, é possível executar programas nativos, como rimraf
, em vez de um gulp-wrapper para um programa nativo, como gulp-rimraf
. Você também pode executar arquivos .exe nativos do Windows, como eu fiz aqui comelevate.exe
ou arquivos * nix nativos no Linux ou Mac.
Tente fazer a mesma coisa com gole. Você terá que esperar alguém aparecer e escrever um gulp-wrapper para o programa nativo que você deseja usar. Além disso, você provavelmente precisará escrever um código complicado como este: (extraído diretamente do repositório angular2-seed )
Código de desenvolvimento 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));
};
Código de produção de gole
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));
};
O código gulp atual é muito mais complicado que isso, pois esse é apenas dois dos vários arquivos gulp presentes no repositório.
Então, qual é mais fácil para você?
Na minha opinião, os scripts do NPM superam em muito o gulp e o grunhido, tanto em eficácia quanto em facilidade de uso, e todos os desenvolvedores de front-end devem considerar usá-lo em seu fluxo de trabalho, pois economiza muito tempo.
ATUALIZAR
Há um cenário que encontrei em que queria usar o Gulp em combinação com scripts NPM e Webpack.
Quando preciso fazer depuração remota em um dispositivo iPad ou Android, por exemplo, preciso iniciar servidores extras. No passado, eu executei todos os servidores como processos separados, no IntelliJ IDEA (ou Webstorm), que é fácil com a Configuração de Execução "Composta". Mas, se eu precisar parar e reiniciá-los, seria entediante fechar cinco guias de servidor diferentes, além de a saída estar espalhada pelas diferentes janelas.
Um dos benefícios do gulp é que é possível encadear toda a saída de processos independentes separados em uma janela do console, que se torna o pai de todos os servidores filhos.
Então, criei uma tarefa gulp muito simples que apenas executa meus scripts do NPM ou os comandos diretamente, para que toda a saída apareça em uma janela e eu possa finalizar facilmente todos os 5 servidores de uma só vez, fechando a janela da tarefa gulp.
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'));
Ainda é um pouco de código apenas para executar 5 tarefas, na minha opinião, mas funciona para esse fim. Uma ressalva é que gulp-shell
parece não executar alguns comandos corretamente, como ios-webkit-debug-proxy
. Então eu tive que criar um script NPM que apenas execute o mesmo comando e funcione.
Portanto, eu uso principalmente scripts NPM para todas as minhas tarefas, mas, ocasionalmente, quando preciso executar vários servidores de uma só vez, inicio minha tarefa Gulp para ajudar. Escolha a ferramenta certa para o trabalho certo.
ATUALIZAÇÃO 2
Agora eu uso um script chamado simultaneamente, que faz a mesma coisa que a tarefa gulp acima. Ele executa vários scripts da CLI em paralelo e canaliza todos eles para a mesma janela do console, e é muito simples de usar. Mais uma vez, nenhum código é necessário (bem, o código está dentro do node_module simultaneamente, mas você não precisa se preocupar com isso)
// 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"
Isso executa todos os 5 scripts em paralelo canalizados para um terminal. Impressionante! Portanto, neste ponto, raramente uso o gulp, pois existem muitos scripts cli para executar as mesmas tarefas sem código.
Eu sugiro que você leia esses artigos que os comparam em profundidade.