Muitos de nós temos que lidar com projetos baseados na web que são usados na produção, que fornecem vários serviços ao público. Ao lidar com esses projetos, é importante ser capaz de construir e implantar nosso código rapidamente. Fazer algo rapidamente muitas vezes leva a erros, especialmente se um processo for repetitivo, portanto, é uma boa prática automatizar tal processo tanto quanto possível.
Neste post, veremos uma ferramenta que pode fazer parte do que nos permitirá alcançar tal automação. Esta ferramenta é um pacote npm chamado Gulp.js. Para se familiarizar com a terminologia básica do Gulp.js usada nesta postagem, consulte “ Uma introdução à automação JavaScript com Gulp ”Que foi publicado anteriormente no blog por Antonios Minas , um de nossos colegas desenvolvedores do ApeeScape. Assumiremos uma familiaridade básica com o ambiente npm, já que ele é usado extensivamente ao longo deste artigo para instalar pacotes.
Antes de continuarmos, vamos voltar algumas etapas para obter uma visão geral do problema que o Gulp.js pode resolver para nós. Muitos projetos baseados na web apresentam arquivos JavaScript front-end que são servidos ao cliente para fornecer várias funcionalidades à página da web. Normalmente, há também um conjunto de folhas de estilo CSS que também são veiculadas para o cliente. Às vezes, ao examinar o código-fonte de um site ou aplicativo da web, podemos ver um código como este:
public/ |- build/ |- js/ |- bundle-{hash}.js |- css/ |- stylesheet-{hash}.css assets/ |- js/ |- vendor/ |- jquery.js |- site.js |- module1.js |- module2.js |- css/ |- main.css |- custom.css gulpfile.js package.json
Existem alguns problemas com este código. Ele tem referências a duas folhas de estilo CSS separadas e quatro arquivos JavaScript separados. Isso significa que o servidor deve fazer um total de seis solicitações ao servidor, e cada solicitação deve carregar separadamente um recurso antes que a página esteja pronta. Isso é menos problemático com HTTP / 2 porque HTTP / 2 apresenta paralelismo e compactação de cabeçalho, mas ainda é um problema. Isso aumenta o volume total de tráfego necessário para carregar esta página e reduz a qualidade da experiência do usuário porque leva mais tempo para carregar os arquivos. No caso do HTTP 1.1, ele também monopoliza a rede e reduz o número de canais de solicitação disponíveis. Teria sido muito melhor combinar os arquivos CSS e JavaScript em um único pacote para cada um. Dessa forma, haveria apenas um total de duas solicitações. Também teria sido bom servir versões reduzidas desses arquivos, que geralmente são muito menores do que os originais. Nosso aplicativo da web também pode falhar se algum dos ativos for armazenado em cache e o cliente receber uma versão desatualizada.
Uma abordagem primitiva para resolver alguns desses problemas é combinar manualmente cada tipo de ativo em um pacote usando um editor de texto e, em seguida, executar o resultado por meio de um serviço de minificador, como http://jscompress.com/ . Isso prova ser muito tedioso de fazer continuamente durante o processo de desenvolvimento. Uma pequena, mas questionável melhoria seria hospedar nosso próprio servidor minificador, usando um dos pacotes disponíveis no GitHub. Então, poderíamos fazer coisas que se pareceriam de alguma forma com o seguinte:
package.json
Isso serviria a arquivos minificados para nosso cliente, mas não resolveria o problema de cache. Isso também causaria carga adicional no servidor, já que nosso servidor essencialmente teria que concatenar e minificar todos os arquivos de origem repetidamente em cada solicitação.
Certamente podemos fazer melhor do que qualquer uma dessas duas abordagens. O que realmente queremos é automatizar o empacotamento e incluí-lo na fase de construção do nosso projeto. Queremos acabar com pacotes de recursos pré-construídos que já estão reduzidos e prontos para veiculação. Também queremos forçar o cliente a receber as versões mais atualizadas de nossos ativos agrupados em cada solicitação, mas ainda queremos aproveitar o cache, se possível. Felizmente para nós, Gulp.js pode lidar com isso. No restante do artigo, estaremos construindo uma solução que aproveitará o poder do Gulp.js para concatenar e minificar os arquivos. Também usaremos um plugin para invadir o cache quando houver atualizações.
s corp vs c corp. exemplo de imposto
Estaremos criando o seguinte diretório e estrutura de arquivos em nosso exemplo:
concat
O npm torna o gerenciamento de pacotes em projetos Node.js uma bênção. Gulp fornece extensibilidade tremenda, aproveitando a abordagem de empacotamento simples do npm para entregar plug-ins modulares e poderosos.O arquivo gulpfile.js é onde definiremos as tarefas que Gulp executará para nós. O npm install --save-dev gulp gulp-concat
é usado pelo npm para definir o pacote de nosso aplicativo e rastrear as dependências que iremos instalar. O diretório público é o que deve ser configurado para enfrentar a web. O diretório de ativos é onde armazenaremos nossos arquivos de origem. Para usar o Gulp no projeto, precisaremos instalá-lo via npm e salvá-lo como uma dependência do desenvolvedor para o projeto. Também queremos começar com var gulp = require('gulp'); var concat = require('gulp-concat'); gulp.task('pack-js', function () { return gulp.src(['assets/js/vendor/*.js', 'assets/js/main.js', 'assets/js/module*.js']) .pipe(concat('bundle.js')) .pipe(gulp.dest('public/build/js')); }); gulp.task('pack-css', function () { return gulp.src(['assets/css/main.css', 'assets/css/custom.css']) .pipe(concat('stylesheet.css')) .pipe(gulp.dest('public/build/css')); }); gulp.task('default', ['pack-js', 'pack-css']);
plugin para o Gulp, que nos permitirá concatenar vários arquivos em um.
Para instalar esses dois itens, executaremos o seguinte comando:
pack-js
Em seguida, queremos começar a escrever o conteúdo de gulpfile.js.
bundle.js
Aqui, estamos carregando a biblioteca gulp e seu plugin concat. Em seguida, definimos três tarefas.
O teste de protótipo de aplicativo móvel pode ser feito manualmente ou pode ser o quê?
A primeira tarefa (public/build/js
) define um procedimento para compactar vários arquivos de origem JavaScript em um pacote. Listamos os arquivos de origem, que serão agrupados, lidos e concatenados na ordem especificada. Colocamos isso no plug-in concat para obter um arquivo final chamado pack-css
. Finalmente, dizemos a gulp para escrever o arquivo em stylesheet.css
.
A segunda tarefa (public/build/css
) faz a mesma coisa que a anterior, mas para as folhas de estilo CSS. Diz ao Gulp para armazenar a saída concatenada como default
em gulp
.
A terceira tarefa (public/build/js/bundle.js
) é aquela que o Gulp executa quando o invocamos sem argumentos. No segundo parâmetro, passamos a lista de outras tarefas a serem executadas quando a tarefa padrão é executada.
Vamos colar este código em gulpfile.js usando qualquer editor de código-fonte que normalmente usamos e, em seguida, salvar o arquivo na raiz do aplicativo.
Em seguida, vamos abrir a linha de comando e executar:
public/build/css/stylesheet.css
Se olharmos nossos arquivos depois de executar este comando, encontraremos dois novos arquivos: npm install --save-dev gulp-clean-css gulp-minify
e var minify = require('gulp-minify'); var cleanCss = require('gulp-clean-css');
. Eles são concatenações de nossos arquivos de origem, o que resolve parte do problema original. No entanto, eles não estão minimizados e ainda não há impedimento de cache. Vamos adicionar a minimização automática.
Precisaremos de dois novos plug-ins. Para adicioná-los, executaremos o seguinte comando:
.pipe(minify()) .pipe(cleanCss())
O primeiro plugin é para minimizar CSS e o segundo é para minimizar JavaScript. O primeiro usa o pacote clean-css, e o segundo usa o pacote UglifyJS2. Vamos carregar esses dois pacotes em nosso gulpfile.js primeiro:
var gulp = require('gulp'); var concat = require('gulp-concat'); var minify = require('gulp-minify'); var cleanCss = require('gulp-clean-css'); gulp.task('pack-js', function () { return gulp.src(['assets/js/vendor/*.js', 'assets/js/main.js', 'assets/js/module*.js']) .pipe(concat('bundle.js')) .pipe(minify()) .pipe(gulp.dest('public/build/js')); }); gulp.task('pack-css', function () { return gulp.src(['assets/css/main.css', 'assets/css/custom.css']) .pipe(concat('stylesheet.css')) .pipe(cleanCss()) .pipe(gulp.dest('public/build/css')); }); gulp.task('default', ['pack-js', 'pack-css']);
Então, precisaremos usá-los em nossas tarefas antes de gravar a saída no disco:
stylesheet.css
O gulpfile.js agora deve ter a seguinte aparência:
bundle.js
Vamos dar um gole novamente. Veremos que o arquivo bundle.js
é salvo em formato reduzido e o arquivo .pipe(minify({ ext:{ min:'.js' }, noSource: true }))
ainda está salvo como está. Notaremos que agora também temos bundle-min.js, que está reduzido. Queremos apenas o arquivo reduzido e salvá-lo como npm install --save-dev gulp-rev
, portanto, modificaremos nosso código com parâmetros adicionais:
var rev = require('gulp-rev');
De acordo com a documentação do plug-in gulp-minify (https://www.npmjs.com/package/gulp-minify), isso definirá o nome desejado para a versão reduzida e dirá ao plug-in para não criar a versão que contém a fonte original. Se excluirmos o conteúdo do diretório de construção e executarmos gulp na linha de comando novamente, acabaremos com apenas dois arquivos minimizados. Acabamos de implementar a fase de minificação de nosso processo de construção.
Em seguida, queremos adicionar impedimento de cache e precisaremos instalar um plug-in para isso:
var gulp = require('gulp'); var concat = require('gulp-concat'); var minify = require('gulp-minify'); var cleanCss = require('gulp-clean-css'); var rev = require('gulp-rev'); gulp.task('pack-js', function () { return gulp.src(['assets/js/vendor/*.js', 'assets/js/main.js', 'assets/js/module*.js']) .pipe(concat('bundle.js')) .pipe(minify({ ext:{ min:'.js' }, noSource: true })) .pipe(rev()) .pipe(gulp.dest('public/build/js')) .pipe(rev.manifest()) .pipe(gulp.dest('public/build')); }); gulp.task('pack-css', function () { return gulp.src(['assets/css/main.css', 'assets/css/custom.css']) .pipe(concat('stylesheet.css')) .pipe(cleanCss()) .pipe(rev()) .pipe(gulp.dest('public/build/css')) .pipe(rev.manifest()) .pipe(gulp.dest('public/build')); }); gulp.task('default', ['pack-js', 'pack-css']);
E exija isso em nosso arquivo gulp:
public/build
Usar o plugin é um pouco complicado. Temos que canalizar a saída reduzida através do plugin primeiro. Então, temos que chamar o plugin novamente depois de gravar os resultados no disco. O plug-in renomeia os arquivos para que sejam marcados com um hash exclusivo e também cria um arquivo de manifesto. O arquivo de manifesto é um mapa que pode ser usado por nosso aplicativo para determinar os nomes de arquivo mais recentes aos quais devemos nos referir em nosso código HTML. Depois de modificar o arquivo gulp, ele deve ficar assim:
var gulp = require('gulp'); var concat = require('gulp-concat'); var minify = require('gulp-minify'); var cleanCss = require('gulp-clean-css'); var rev = require('gulp-rev'); gulp.task('pack-js', function () { return gulp.src(['assets/js/vendor/*.js', 'assets/js/main.js', 'assets/js/module*.js']) .pipe(concat('bundle.js')) .pipe(minify({ ext:{ min:'.js' }, noSource: true })) .pipe(rev()) .pipe(gulp.dest('public/build/js')) .pipe(rev.manifest('public/build/rev-manifest.json', { merge: true })) .pipe(gulp.dest('')); }); gulp.task('pack-css', function () { return gulp.src(['assets/css/main.css', 'assets/css/custom.css']) .pipe(concat('stylesheet.css')) .pipe(cleanCss()) .pipe(rev()) .pipe(gulp.dest('public/build/css')) .pipe(rev.manifest('public/build/rev-manifest.json', { merge: true })) .pipe(gulp.dest('')); }); gulp.task('default', ['pack-js', 'pack-css']);
Com o bloqueio de cache adequado no lugar, você pode enlouquecer com o longo tempo de expiração para seus arquivos JS e CSS e substituí-los de forma confiável por versões mais recentes sempre que necessário.Vamos deletar o conteúdo de nosso diretório de construção e executar gulp novamente. Veremos que agora temos dois arquivos com hashtags afixados a cada um dos nomes de arquivo e um manifest.json salvo em rev.manifest()
. Se abrirmos o arquivo de manifesto, veremos que ele contém apenas uma referência a um de nossos arquivos minimizados e marcados. O que está acontecendo é que cada tarefa grava um arquivo de manifesto separado, e uma delas acaba substituindo a outra. Precisaremos modificar as tarefas com parâmetros adicionais que dirão a eles para procurar o arquivo de manifesto existente e mesclar os novos dados nele, se existir. A sintaxe para isso é um pouco complicada, então vamos dar uma olhada na aparência do código e depois examiná-lo:
rev-manifest.json
Estamos canalizando a saída para rev.manifest()
primeiro. Isso cria arquivos marcados em vez dos arquivos que tínhamos antes. Estamos fornecendo o caminho desejado de nosso npm install --save-dev del
e informando var del = require('del'); gulp.task('clean-js', function () { return del([ 'public/build/js/*.js' ]); }); gulp.task('clean-css', function () { return del([ 'public/build/css/*.css' ]); });
para mesclar no arquivo existente, se ele existir. Então, estamos dizendo ao gulp para gravar o manifesto no diretório atual, que nesse ponto será público / compilado. O problema do caminho é devido a um bug que é discutido com mais detalhes no GitHub.
onde posso aprender c ++
Agora temos minificação automática, arquivos marcados e um arquivo de manifesto. Tudo isso nos permitirá entregar os arquivos mais rapidamente ao usuário e quebrar seu cache sempre que fizermos nossas modificações. No entanto, existem apenas dois problemas restantes.
O primeiro problema é que, se fizermos quaisquer modificações em nossos arquivos de origem, obteremos os arquivos recém-marcados, mas os antigos também permanecerão lá. Precisamos de alguma forma de excluir automaticamente os arquivos minificados antigos. Vamos resolver esse problema usando um plug-in que nos permitirá excluir arquivos:
gulp.task('pack-js', ['clean-js'], function () { gulp.task('pack-css', ['clean-css'], function () {
Vamos exigi-lo em nosso código e definir duas novas tarefas, uma para cada tipo de arquivo de origem:
gulp
Em seguida, teremos certeza de que a execução da nova tarefa será concluída antes de nossas duas tarefas principais:
gulp.task('watch', function() { gulp.watch('assets/js/**/*.js', ['pack-js']); gulp.watch('assets/css/**/*.css', ['pack-css']); });
Se executarmos gulp.task('default', ['watch']);
novamente após essa modificação, teremos apenas os arquivos minimizados mais recentes.
O segundo problema é que não queremos continuar engolindo em seco toda vez que fazemos uma mudança. Para resolver isso, precisaremos definir uma tarefa do inspetor:
pack-js
Também mudaremos a definição de nossa tarefa padrão:
pack-css
Se agora executarmos o gulp a partir da linha de comando, descobriremos que ele não cria mais nada na invocação. Isso ocorre porque agora ele chama a tarefa do inspetor que observará nossos arquivos de origem em busca de quaisquer alterações e construirá apenas quando detectar uma alteração. Se tentarmos alterar qualquer um de nossos arquivos de origem e, em seguida, olharmos para nosso console novamente, veremos que o gulp(‘bundle.js’)
e
Agora, tudo o que precisamos fazer é carregar o arquivo manifest.json em nosso aplicativo e obter os nomes de arquivo marcados a partir dele. A maneira como fazemos isso depende de nossa linguagem de back-end e pilha de tecnologia específicas, e seria muito trivial de implementar, portanto, não vamos examinar isso em detalhes. No entanto, a ideia geral é que podemos carregar o manifesto em uma matriz ou objeto e, em seguida, definir uma função auxiliar que nos permitirá chamar ativos com versão de nossos modelos de maneira semelhante a esta:
Assim que fizermos isso, nunca mais teremos que nos preocupar com as tags alteradas em nossos nomes de arquivo e seremos capazes de nos concentrar na escrita de código de alta qualidade.
qual área de uma rede é uma área importante de vulnerabilidade potencial devido ao uso de urls?
O código-fonte final deste artigo, junto com alguns recursos de amostra, pode ser encontrado em este repositório GitHub .
Neste artigo, vimos como implementar a automação baseada em Gulp para nosso processo de construção. Espero que isso seja útil para você e lhe permita desenvolver processos de construção mais sofisticados em seus próprios aplicativos.
Lembre-se de que o Gulp é apenas uma das ferramentas que podem ser usadas para essa finalidade, e existem muitas outras, como Grunt, Browserify e Webpack. Eles variam em seus propósitos e no escopo dos problemas que podem resolver. Alguns podem resolver problemas que o Gulp não consegue, como agrupamento JavaScript módulos com dependências que podem ser carregadas sob demanda. Isso é conhecido como “divisão de código” e é uma melhoria em relação à ideia de servir um grande arquivo com todas as partes de nosso programa em cada página. Essas ferramentas são bastante sofisticadas, mas podem ser abordadas no futuro. Em uma postagem a seguir, veremos como automatizar a implantação de nosso aplicativo.
Relacionado: Gulp Under the Hood: Construindo uma ferramenta de automação de tarefas baseada em fluxo