作者都是各自领域经过审查的专家,并撰写他们有经验的主题. 我们所有的内容都经过同行评审,并由同一领域的Toptal专家验证.
安东·卡内夫斯基的头像

安东Kanevsky

CS学士学位,15年以上全栈开发经验, Anton是一名专业的软件工程师,他交付了许多复杂的项目.

工作经验

13

分享

我们中的许多人都必须处理在生产中使用的基于web的项目, 哪些机构为市民提供各种服务. 在处理此类项目时,能够快速构建和部署代码是很重要的. 快速做事往往会导致错误, 特别是如果一个过程是重复的, 因此,将这样的过程尽可能自动化是一个很好的实践.

狼吞虎咽地吃:网站开发人员最大化网站速度的秘密武器

我的开发者朋友们:没有任何借口为你的浏览器提供垃圾服务.

在这篇文章中, 我们将看到一个工具,可以是什么将使我们实现这样的自动化的一部分. 这个工具是一个名为狼吞虎咽地吃的npm包.js. 为了熟悉基本的狼吞虎咽地吃.本文中使用的Js术语,请参考“用狼吞虎咽地吃介绍JavaScript自动化,这篇文章之前发表在博客上 安东尼奥米纳斯他是我们Toptal的同事之一. 我们将假设对npm环境有基本的了解, 因为它在本文中被广泛用于安装软件包.

服务前端资产

在我们继续之前,让我们先回顾一下狼吞虎咽地吃所面临的问题.j可以解出来. 许多基于web的项目都以前端JavaScript文件为特征,这些文件被提供给客户端,以便为网页提供各种功能. 通常也有一组CSS样式表提供给客户端. 有时在查看网站或web应用程序的源代码时, 我们可以看到这样的代码:







这段代码有几个问题. 它引用了两个独立的CSS样式表和四个独立的JavaScript文件. 这意味着服务器必须向服务器发出总共6个请求, 在页面准备好之前,每个请求都必须单独加载一个资源. 这在HTTP/2中不是问题,因为HTTP/2引入了并行性和报头压缩, 但这仍然是个问题. 它增加了加载此页面所需的总流量,并降低了用户体验的质量,因为加载文件需要更长的时间. 对于HTTP 1.1,它还占用网络并减少可用请求通道的数量. 如果将CSS和JavaScript文件分别合并到一个包中,效果会好得多. 这样,总共就只有两个请求. 如果提供这些文件的缩小版本也会很好, 它们通常比原件小得多. 如果任何资产被缓存,我们的web应用程序也可能会崩溃, 客户端会收到一个过时的版本.

过载

解决其中一些问题的一种基本方法是使用文本编辑器手动将每种类型的资产组合到一个包中, 然后运行结果 通过minifier服务,例如 http://jscompress.com/. 事实证明,在开发过程中持续这样做是非常乏味的. 一个小小的但值得怀疑的改进是托管我们自己的迷你服务器, 使用GitHub上可用的软件包之一. 然后我们可以做一些类似于下面的事情:


这将为我们的客户端提供缩小的文件,但它不能解决缓存问题. 它还会给服务器带来额外的负载,因为我们的服务器实际上必须对每个请求重复地连接和最小化所有源文件.

使用狼吞虎咽地吃实现自动化.js

当然,我们可以比这两种方法中的任何一种做得更好. 我们真正想要的是自动化捆绑,并将其包含在项目的构建阶段. 我们希望以已经缩小并准备好服务的预构建资产包结束. 我们还希望强制客户端在每次请求时都接收到我们所捆绑资产的最新版本, 但是如果可能的话,我们仍然希望利用缓存. 幸运的是,狼吞虎咽地吃.Js可以处理这个. 在本文的其余部分中,我们将构建一个利用狼吞虎咽地吃功能的解决方案.Js来连接和缩小文件. 当有更新时,我们还将使用一个插件来破坏缓存.

在我们的示例中,我们将创建以下目录和文件结构:

公共/
| - - - - - -构建/
   |- js/
      | - 包{哈希}.js
   | - css /
      | -样式表{哈希}.css
资产/
|- js/
   | -供应商/
   | - jquery.js
   | - - - - - -网站.js
   | - module1.js
   | - module2.js
| - css /
   | - - - - - -主.css
   | - - - - - -自定义.css
狼吞虎咽地吃file.js
包.json
npm在节点中进行包管理.Js投射出一种幸福. 狼吞虎咽地吃通过利用npm的简单打包方式来提供模块化和强大的插件,从而提供了巨大的可扩展性.

的狼吞虎咽地吃file.我们将在这里定义狼吞虎咽地吃将为我们执行的任务. 的 包.json 被NPM用来定义我们的应用程序包,并跟踪我们将要安装的依赖. 公共目录应该配置成面向web的目录. 的 资产目录 我们将在哪里存储源文件. 在项目中使用狼吞虎咽地吃, 我们需要通过NPM安装它,并将其保存为项目的开发者依赖项. 我们也要从 concat 狼吞虎咽地吃插件,它允许我们将多个文件连接成一个.

为了安装这两个项目,我们将运行以下命令:

NPM install——save-dev 狼吞虎咽地吃

接下来,我们将开始编写狼吞虎咽地吃file的内容.js.

Var 狼吞虎咽地吃 = require('狼吞虎咽地吃');
Var concat = require('狼吞虎咽地吃-concat');
 
狼吞虎咽地吃.Task ('pack-js', function () {    
    返回吞咽.src([资产/ js /供应商/ *.js”、“资产/ js /主要.js”、“资产/ js /模块*.js'])
        .管(concat('包.js'))
        .管(吞咽.桌子('公共/构建/ js '));
});
 
狼吞虎咽地吃.Task ('pack-css的, function () {    
    返回吞咽.src([资产/ css /主要.css”、“资产/ css /自定义.css '])
        .管(concat(样式表.css '))
        .管(吞咽.桌子(公共/构建/ css));
});
 
狼吞虎咽地吃.Task ('默认的', ['pack-js', 'pack-css ']);

这里,我们正在加载狼吞虎咽地吃库及其concat插件. 然后我们定义三个任务.

加载狼吞虎咽地吃库及其concat插件

第一项任务(pack-js)定义了一个过程来将多个JavaScript源文件压缩到一个包中. 我们列出源文件,这些文件将按照指定的顺序进行全局化、读取和连接. 我们将其管道到concat插件中以获得一个最终文件 包.js. 最后,我们告诉狼吞虎咽地吃将文件写入 公共/构建/ js.

第二项任务(pack-css)做同样的事情,但对于CSS样式表. 它告诉狼吞虎咽地吃将连接的输出存储为 样式表.css in 公共/构建/ css.

第三项任务(默认的)是当我们不带参数调用它时狼吞虎咽地吃运行的. 在第二个参数中,我们传递默认任务运行时要执行的其他任务列表.

让我们将这些代码粘贴到狼吞虎咽地吃file中.使用我们通常使用的任何源代码编辑器,然后将文件保存到应用程序的根目录.

接下来,我们将打开命令行并运行:

狼吞虎咽地吃

如果我们在运行此命令后查看我们的文件,我们将发现两个新文件: 公共/构建/ js /包.js公共/构建/ css样式表.css. 它们是源文件的连接,解决了部分原始问题. 然而,它们并没有被最小化,也没有缓存破坏. 让我们添加自动缩小功能.

优化已建资产

我们将需要两个新的插件. 要添加它们,我们将运行以下命令:

狼吞虎咽地吃-clean-css 狼吞虎咽地吃-minify

第一个插件用于缩小CSS,第二个插件用于缩小JavaScript. 第一个使用clean-css包,第二个使用UglifyJS2包. 我们将在我们的狼吞虎咽地吃file中加载这两个包.js:

Var minify = require('狼吞虎咽地吃-minify');
var cleanCss = require('狼吞虎咽地吃-clean-css的);

然后,在将输出写入磁盘之前,我们需要在任务中使用它们:

.管(贬低())
.管(cleanCss ())

的狼吞虎咽地吃file.Js现在看起来像这样:

Var 狼吞虎咽地吃 = require('狼吞虎咽地吃');
Var concat = require('狼吞虎咽地吃-concat');
Var minify = require('狼吞虎咽地吃-minify');
var cleanCss = require('狼吞虎咽地吃-clean-css的);
 
狼吞虎咽地吃.Task ('pack-js', function () {    
    返回吞咽.src([资产/ js /供应商/ *.js”、“资产/ js /主要.js”、“资产/ js /模块*.js'])
        .管(concat('包.js'))
        .管(贬低())
        .管(吞咽.桌子('公共/构建/ js '));
});
 
狼吞虎咽地吃.Task ('pack-css的, function () {    
    返回吞咽.src([资产/ css /主要.css”、“资产/ css /自定义.css '])
        .管(concat(样式表.css '))
        .管(cleanCss ())
   .管(吞咽.桌子(公共/构建/ css));
});
 
狼吞虎咽地吃.Task ('默认的', ['pack-js', 'pack-css ']);

让我们再跑一遍. 我们将看到文件 样式表.css 以缩小格式保存,文件 包.js 还是保存原样吗. 我们会注意到我们现在也有了包-min.Js,它是最小化的. 我们只需要缩小后的文件,并将其保存为 包.js,所以我们将用额外的参数修改代码:

.管(贬低({
    ext: {
        敏:“.js'
    },
    noSource:真
}))

根据狼吞虎咽地吃-minify插件文档(http://www.npmjs.com/包/狼吞虎咽地吃-minify), 这将为缩小版本设置所需的名称, 并告诉插件不要创建包含原始源代码的版本. 如果我们删除构建目录的内容并再次从命令行运行狼吞虎咽地吃, 我们最终将得到两个缩小的文件. 我们刚刚完成了构建过程的最小化阶段的实现.

缓存的地沟油

接下来,我们想要添加缓存破坏,我们需要为此安装一个插件:

NPM install——save-dev 狼吞虎咽地吃-牧师

并在我们的狼吞虎咽地吃文件中要求它:

Var 牧师 = require('狼吞虎咽地吃-牧师');

使用这个插件有点棘手. 我们必须首先通过插件将缩小后的输出管道化. 然后,我们必须在将结果写入磁盘后再次调用插件. 该插件重命名文件,以便用唯一的散列标记它们, 它还创建了一个清单文件. manifest文件是一个映射,应用程序可以使用它来确定我们应该在HTML代码中引用的最新文件名. 在我们修改了狼吞虎咽地吃文件之后,它应该看起来像这样:

Var 狼吞虎咽地吃 = require('狼吞虎咽地吃');
Var concat = require('狼吞虎咽地吃-concat');
Var minify = require('狼吞虎咽地吃-minify');
var cleanCss = require('狼吞虎咽地吃-clean-css的);
Var 牧师 = require('狼吞虎咽地吃-牧师');
 
狼吞虎咽地吃.Task ('pack-js', function () {    
    返回吞咽.src([资产/ js /供应商/ *.js”、“资产/ js /主要.js”、“资产/ js /模块*.js'])
        .管(concat('包.js'))
        .管(贬低({
            ext: {
                敏:“.js'
            },
            noSource:真
        }))
        .管(牧师())
        .管(吞咽.桌子(公共/构建/ js))
        .管(牧师.清单())
        .管(吞咽.桌子('公共/构建'));
});
 
狼吞虎咽地吃.Task ('pack-css的, function () {
    返回吞咽.src([资产/ css /主要.css”、“资产/ css /自定义.css '])
        .管(concat(样式表.css '))
        .管(cleanCss ())
        .管(牧师())
            .管(吞咽.桌子(公共/构建/ css))
        .管(牧师.清单())
        .管(吞咽.桌子('公共/构建'));
});
 
狼吞虎咽地吃.Task ('默认的', ['pack-js', 'pack-css ']);
适当的缓存破坏, 你可以为你的JS和CSS文件设置很长的过期时间,并在必要的时候用更新的版本替换它们.

让我们删除构建目录的内容并再次运行狼吞虎咽地吃. 我们将发现,现在有两个文件,每个文件名都附有hashtag, 还有一张清单.Json保存到 公共/构建. 如果我们打开舱单文件, 我们将看到它只有一个对我们的缩小和标记文件之一的引用. 发生了什么是每个任务写一个单独的清单文件, 其中一个会覆盖另一个. 我们需要用额外的参数来修改任务,这些参数将告诉它们寻找现有的清单文件,并在存在的情况下将新数据合并到其中. 它的语法有点复杂, 那么让我们看看代码应该是什么样子,然后再看一遍:

Var 狼吞虎咽地吃 = require('狼吞虎咽地吃');
Var concat = require('狼吞虎咽地吃-concat');
Var minify = require('狼吞虎咽地吃-minify');
var cleanCss = require('狼吞虎咽地吃-clean-css的);
Var 牧师 = require('狼吞虎咽地吃-牧师');
 
狼吞虎咽地吃.Task ('pack-js', function () {
    返回吞咽.src([资产/ js /供应商/ *.js”、“资产/ js /主要.js”、“资产/ js /模块*.js'])
        .管(concat('包.js'))
        .管(贬低({
            ext: {
                敏:“.js'
            },
            noSource:真
        }))
        .管(牧师())
        .管(吞咽.桌子(公共/构建/ js))
        .管(牧师.清单(“公共/构建/ 牧师-manifest.json, {
            合并:真
        }))
        .管(吞咽.桌子("));
    });
 
狼吞虎咽地吃.Task ('pack-css的, function () {    
    返回吞咽.src([资产/ css /主要.css”、“资产/ css /自定义.css '])
        .管(concat(样式表.css '))
        .管(cleanCss ())
        .管(牧师())
        .管(吞咽.桌子(公共/构建/ css))
        .管(牧师.清单(“公共/构建/ 牧师-manifest.json, {
            合并:真
        }))
        .管(吞咽.桌子("));
});
 
狼吞虎咽地吃.Task ('默认的', ['pack-js', 'pack-css ']);

我们将输出管道输出到 牧师.清单() 第一个. 这将创建带有标记的文件,而不是我们之前使用的文件. 我们正在提供我们想要的路径 牧师-manifest.json和告诉 牧师.清单() 如果现有文件存在,则合并到现有文件. 然后我们告诉狼吞虎咽地吃将清单写入当前目录, 到那个时候,哪个是公共的/建设的. 路径问题是由于一个bug,在GitHub上有更详细的讨论.

我们现在有了自动缩小、标记文件和清单文件. 所有这些都将使我们能够更快地将文件传递给用户, 只要我们做了修改,就会破坏他们的缓存. 不过,还剩下两个问题.

第一个问题是,如果我们对源文件进行任何修改, 我们将获得新标记的文件, 但旧的也会留在那里. 我们需要一些方法来自动删除旧的缩小文件. 让我们使用一个允许我们删除文件的插件来解决这个问题:

NPM install——save-dev del

我们将在代码中需要它并定义两个新任务,一个用于每种类型的源文件:

Var del = require('del');
 
狼吞虎咽地吃.Task ('clean-js', function () {
    返回德尔([
        “公共/构建/ js / *.js'
    ]);
});
 
狼吞虎咽地吃.任务('clean-css的,函数(){
    返回德尔([
        “公共/构建/ css / *.css的
    ]);
});

然后,我们将确保新任务在我们的两个主要任务之前完成运行:

狼吞虎咽地吃.任务('pack-js', ['clean-js'],函数(){
狼吞虎咽地吃.任务('pack-css的, ['clean-css的],函数(){

如果我们跑 狼吞虎咽地吃 同样,在此修改之后,我们将拥有最新的缩小文件.

第二个问题是,我们不希望每次进行更改时都保持快速运行. 为了解决这个问题,我们需要定义一个观察者任务:

狼吞虎咽地吃.Task ('watch', function() {
 狼吞虎咽地吃.看(资产/ js / * * / *.js”,[' pack-js ']);
 狼吞虎咽地吃.看(资产/ css / * * / *.css”,[' pack-css ']);
});

我们还将更改默认任务的定义:

狼吞虎咽地吃.任务(“违约”,['看']);

如果我们现在从命令行运行狼吞虎咽地吃, 我们将发现它在调用时不再构建任何东西. 这是因为它现在调用监视器任务,该任务将监视源文件的任何更改, 并且仅在检测到更改时进行构建. 如果我们尝试更改任何源文件,然后再次查看控制台,我们将看到 pack-jspack-css 任务与其依赖项一起自动运行.

现在,我们要做的就是装载舱单.Json文件,并从中获取带标签的文件名. 我们如何做到这一点取决于我们特定的后端语言和技术堆栈, 实现起来也很简单, 所以我们就不详细讲了. 然而, 总体思路是,我们可以将清单加载到数组或对象中, 然后定义一个辅助函数,允许我们以类似于以下的方式从模板中调用版本化的资产:

杯(包.js’)

一旦我们这样做了, 我们再也不用担心文件名中的标签被更改了, 我们将能够专注于编写高质量的代码.

本文的最终源代码以及一些样例资产可以在 这个GitHub存储库.

结论

在本文中,我们讨论了如何为构建过程实现基于狼吞虎咽地吃的自动化. 我希望这对您有所帮助,并允许您在自己的应用程序中开发更复杂的构建过程.

请记住,狼吞虎咽地吃只是可用于此目的的工具之一, 还有很多其他的,比如Grunt, Browserify, 和Webpack. 它们的目的和解决问题的范围各不相同. 有些可以解决狼吞虎咽地吃无法解决的问题,比如捆绑 JavaScript 具有依赖关系的模块可以按需加载. 这被称为“代码分割”。, 相对于在每个页面上提供一个大文件并包含程序的所有部分的想法,这是一种改进. 这些工具相当复杂,但将来可能会涉及到. 在下面的文章中,我们将讨论如何自动部署应用程序.

聘请Toptal这方面的专家.
现在雇佣
安东·卡内夫斯基的头像
安东Kanevsky

位于 东梅多,纽约,美国

成员自 2016年3月28日

作者简介

CS学士学位,15年以上全栈开发经验, Anton是一名专业的软件工程师,他交付了许多复杂的项目.

Toptal作者都是各自领域经过审查的专家,并撰写他们有经验的主题. 我们所有的内容都经过同行评审,并由同一领域的Toptal专家验证.

工作经验

13

世界级的文章,每周发一次.

订阅意味着同意我们的 隐私政策

世界级的文章,每周发一次.

订阅意味着同意我们的 隐私政策

Toptal开发者

加入总冠军® 社区.

\n\n\n\n\n\n

这段代码有几个问题. 它引用了两个独立的CSS样式表和四个独立的JavaScript文件. 这意味着服务器必须向服务器发出总共6个请求, 在页面准备好之前,每个请求都必须单独加载一个资源. 这在HTTP/2中不是问题,因为HTTP/2引入了并行性和报头压缩, 但这仍然是个问题. 它增加了加载此页面所需的总流量,并降低了用户体验的质量,因为加载文件需要更长的时间. 对于HTTP 1.1,它还占用网络并减少可用请求通道的数量. 如果将CSS和JavaScript文件分别合并到一个包中,效果会好得多. 这样,总共就只有两个请求. 如果提供这些文件的缩小版本也会很好, 它们通常比原件小得多. 如果任何资产被缓存,我们的web应用程序也可能会崩溃, 客户端会收到一个过时的版本.

\n\n

\"过载\"

\n\n

解决其中一些问题的一种基本方法是使用文本编辑器手动将每种类型的资产组合到一个包中, 然后运行结果 通过minifier服务,例如 http://jscompress.com/. 事实证明,在开发过程中持续这样做是非常乏味的. 一个小小的但值得怀疑的改进是托管我们自己的迷你服务器, 使用GitHub上可用的软件包之一. 然后我们可以做一些类似于下面的事情:

\n\n
\n
\n\n

这将为我们的客户端提供缩小的文件,但它不能解决缓存问题. 它还会给服务器带来额外的负载,因为我们的服务器实际上必须对每个请求重复地连接和最小化所有源文件.

\n\n

使用狼吞虎咽地吃实现自动化.js

\n\n

当然,我们可以比这两种方法中的任何一种做得更好. 我们真正想要的是自动化捆绑,并将其包含在项目的构建阶段. 我们希望以已经缩小并准备好服务的预构建资产包结束. 我们还希望强制客户端在每次请求时都接收到我们所捆绑资产的最新版本, 但是如果可能的话,我们仍然希望利用缓存. 幸运的是,狼吞虎咽地吃.Js可以处理这个. 在本文的其余部分中,我们将构建一个利用狼吞虎咽地吃功能的解决方案.Js来连接和缩小文件. 当有更新时,我们还将使用一个插件来破坏缓存.

\n\n

在我们的示例中,我们将创建以下目录和文件结构:

\n\n
公共/\n| - - - - - -构建/\n   |- js/\n      | - 包{哈希}.js\n   | - css /\n      | -样式表{哈希}.css\n资产/\n|- js/\n   | -供应商/\n   | - jquery.js\n   | - - - - - -网站.js\n   | - module1.js\n   | - module2.js\n| - css /\n   | - - - - - -主.css\n   | - - - - - -自定义.css\n狼吞虎咽地吃file.js\n包.json\n
\n\n
npm在节点中进行包管理.Js投射出一种幸福. 狼吞虎咽地吃通过利用npm的简单打包方式来提供模块化和强大的插件,从而提供了巨大的可扩展性.
\n\n

的狼吞虎咽地吃file.我们将在这里定义狼吞虎咽地吃将为我们执行的任务. 的 包.json 被NPM用来定义我们的应用程序包,并跟踪我们将要安装的依赖. 公共目录应该配置成面向web的目录. 的 资产目录 我们将在哪里存储源文件. 在项目中使用狼吞虎咽地吃, 我们需要通过NPM安装它,并将其保存为项目的开发者依赖项. 我们也要从 concat 狼吞虎咽地吃插件,它允许我们将多个文件连接成一个.

\n\n

为了安装这两个项目,我们将运行以下命令:

\n\n
NPM install——save-dev 狼吞虎咽地吃\n
\n\n

接下来,我们将开始编写狼吞虎咽地吃file的内容.js.

\n\n
Var 狼吞虎咽地吃 = require('狼吞虎咽地吃');\nVar concat = require('狼吞虎咽地吃-concat');\n \n狼吞虎咽地吃.Task ('pack-js', function () {    \n    返回吞咽.src([资产/ js /供应商/ *.js”、“资产/ js /主要.js”、“资产/ js /模块*.js'])\n        .管(concat('包.js'))\n        .管(吞咽.桌子('公共/构建/ js '));\n});\n \n狼吞虎咽地吃.Task ('pack-css的, function () {    \n    返回吞咽.src([资产/ css /主要.css”、“资产/ css /自定义.css '])\n        .管(concat(样式表.css '))\n        .管(吞咽.桌子(公共/构建/ css));\n});\n \n狼吞虎咽地吃.Task ('默认的', ['pack-js', 'pack-css ']);\n
\n\n

这里,我们正在加载狼吞虎咽地吃库及其concat插件. 然后我们定义三个任务.

\n\n

\"加载狼吞虎咽地吃库及其concat插件\"

\n\n

第一项任务(pack-js)定义了一个过程来将多个JavaScript源文件压缩到一个包中. 我们列出源文件,这些文件将按照指定的顺序进行全局化、读取和连接. 我们将其管道到concat插件中以获得一个最终文件 包.js. 最后,我们告诉狼吞虎咽地吃将文件写入 公共/构建/ js.

\n\n

第二项任务(pack-css)做同样的事情,但对于CSS样式表. 它告诉狼吞虎咽地吃将连接的输出存储为 样式表.css in 公共/构建/ css.

\n\n

第三项任务(默认的)是当我们不带参数调用它时狼吞虎咽地吃运行的. 在第二个参数中,我们传递默认任务运行时要执行的其他任务列表.

\n\n

让我们将这些代码粘贴到狼吞虎咽地吃file中.使用我们通常使用的任何源代码编辑器,然后将文件保存到应用程序的根目录.

\n\n

接下来,我们将打开命令行并运行:

\n\n
狼吞虎咽地吃\n
\n\n

如果我们在运行此命令后查看我们的文件,我们将发现两个新文件: 公共/构建/ js /包.js公共/构建/ css样式表.css. 它们是源文件的连接,解决了部分原始问题. 然而,它们并没有被最小化,也没有缓存破坏. 让我们添加自动缩小功能.

\n\n

优化已建资产

\n\n

我们将需要两个新的插件. 要添加它们,我们将运行以下命令:

\n\n
狼吞虎咽地吃-clean-css 狼吞虎咽地吃-minify\n
\n\n

第一个插件用于缩小CSS,第二个插件用于缩小JavaScript. 第一个使用clean-css包,第二个使用UglifyJS2包. 我们将在我们的狼吞虎咽地吃file中加载这两个包.js:

\n\n
Var minify = require('狼吞虎咽地吃-minify');\nvar cleanCss = require('狼吞虎咽地吃-clean-css的);\n
\n\n

然后,在将输出写入磁盘之前,我们需要在任务中使用它们:

\n\n
.管(贬低())\n.管(cleanCss ())\n
\n\n

的狼吞虎咽地吃file.Js现在看起来像这样:

\n\n
Var 狼吞虎咽地吃 = require('狼吞虎咽地吃');\nVar concat = require('狼吞虎咽地吃-concat');\nVar minify = require('狼吞虎咽地吃-minify');\nvar cleanCss = require('狼吞虎咽地吃-clean-css的);\n \n狼吞虎咽地吃.Task ('pack-js', function () {    \n    返回吞咽.src([资产/ js /供应商/ *.js”、“资产/ js /主要.js”、“资产/ js /模块*.js'])\n        .管(concat('包.js'))\n        .管(贬低())\n        .管(吞咽.桌子('公共/构建/ js '));\n});\n \n狼吞虎咽地吃.Task ('pack-css的, function () {    \n    返回吞咽.src([资产/ css /主要.css”、“资产/ css /自定义.css '])\n        .管(concat(样式表.css '))\n        .管(cleanCss ())\n   .管(吞咽.桌子(公共/构建/ css));\n});\n \n狼吞虎咽地吃.Task ('默认的', ['pack-js', 'pack-css ']);\n
\n\n

让我们再跑一遍. 我们将看到文件 样式表.css 以缩小格式保存,文件 包.js 还是保存原样吗. 我们会注意到我们现在也有了包-min.Js,它是最小化的. 我们只需要缩小后的文件,并将其保存为 包.js,所以我们将用额外的参数修改代码:

\n\n
.管(贬低({\n    ext: {\n        敏:“.js'\n    },\n    noSource:真\n}))\n
\n\n

根据狼吞虎咽地吃-minify插件文档(http://www.npmjs.com/包/狼吞虎咽地吃-minify), 这将为缩小版本设置所需的名称, 并告诉插件不要创建包含原始源代码的版本. 如果我们删除构建目录的内容并再次从命令行运行狼吞虎咽地吃, 我们最终将得到两个缩小的文件. 我们刚刚完成了构建过程的最小化阶段的实现.

\n\n

缓存的地沟油

\n\n

接下来,我们想要添加缓存破坏,我们需要为此安装一个插件:

\n\n
NPM install——save-dev 狼吞虎咽地吃-牧师\n
\n\n

并在我们的狼吞虎咽地吃文件中要求它:

\n\n
Var 牧师 = require('狼吞虎咽地吃-牧师');\n
\n\n

使用这个插件有点棘手. 我们必须首先通过插件将缩小后的输出管道化. 然后,我们必须在将结果写入磁盘后再次调用插件. 该插件重命名文件,以便用唯一的散列标记它们, 它还创建了一个清单文件. manifest文件是一个映射,应用程序可以使用它来确定我们应该在HTML代码中引用的最新文件名. 在我们修改了狼吞虎咽地吃文件之后,它应该看起来像这样:

\n\n
Var 狼吞虎咽地吃 = require('狼吞虎咽地吃');\nVar concat = require('狼吞虎咽地吃-concat');\nVar minify = require('狼吞虎咽地吃-minify');\nvar cleanCss = require('狼吞虎咽地吃-clean-css的);\nVar 牧师 = require('狼吞虎咽地吃-牧师');\n \n狼吞虎咽地吃.Task ('pack-js', function () {    \n    返回吞咽.src([资产/ js /供应商/ *.js”、“资产/ js /主要.js”、“资产/ js /模块*.js'])\n        .管(concat('包.js'))\n        .管(贬低({\n            ext: {\n                敏:“.js'\n            },\n            noSource:真\n        }))\n        .管(牧师())\n        .管(吞咽.桌子(公共/构建/ js))\n        .管(牧师.清单())\n        .管(吞咽.桌子('公共/构建'));\n});\n \n狼吞虎咽地吃.Task ('pack-css的, function () {\n    返回吞咽.src([资产/ css /主要.css”、“资产/ css /自定义.css '])\n        .管(concat(样式表.css '))\n        .管(cleanCss ())\n        .管(牧师())\n            .管(吞咽.桌子(公共/构建/ css))\n        .管(牧师.清单())\n        .管(吞咽.桌子('公共/构建'));\n});\n \n狼吞虎咽地吃.Task ('默认的', ['pack-js', 'pack-css ']);\n
\n\n
适当的缓存破坏, 你可以为你的JS和CSS文件设置很长的过期时间,并在必要的时候用更新的版本替换它们.
\n\n

让我们删除构建目录的内容并再次运行狼吞虎咽地吃. 我们将发现,现在有两个文件,每个文件名都附有hashtag, 还有一张清单.Json保存到 公共/构建. 如果我们打开舱单文件, 我们将看到它只有一个对我们的缩小和标记文件之一的引用. 发生了什么是每个任务写一个单独的清单文件, 其中一个会覆盖另一个. 我们需要用额外的参数来修改任务,这些参数将告诉它们寻找现有的清单文件,并在存在的情况下将新数据合并到其中. 它的语法有点复杂, 那么让我们看看代码应该是什么样子,然后再看一遍:

\n\n
Var 狼吞虎咽地吃 = require('狼吞虎咽地吃');\nVar concat = require('狼吞虎咽地吃-concat');\nVar minify = require('狼吞虎咽地吃-minify');\nvar cleanCss = require('狼吞虎咽地吃-clean-css的);\nVar 牧师 = require('狼吞虎咽地吃-牧师');\n \n狼吞虎咽地吃.Task ('pack-js', function () {\n    返回吞咽.src([资产/ js /供应商/ *.js”、“资产/ js /主要.js”、“资产/ js /模块*.js'])\n        .管(concat('包.js'))\n        .管(贬低({\n            ext: {\n                敏:“.js'\n            },\n            noSource:真\n        }))\n        .管(牧师())\n        .管(吞咽.桌子(公共/构建/ js))\n        .管(牧师.清单(“公共/构建/ 牧师-manifest.json, {\n            合并:真\n        }))\n        .管(吞咽.桌子("));\n    });\n \n狼吞虎咽地吃.Task ('pack-css的, function () {    \n    返回吞咽.src([资产/ css /主要.css”、“资产/ css /自定义.css '])\n        .管(concat(样式表.css '))\n        .管(cleanCss ())\n        .管(牧师())\n        .管(吞咽.桌子(公共/构建/ css))\n        .管(牧师.清单(“公共/构建/ 牧师-manifest.json, {\n            合并:真\n        }))\n        .管(吞咽.桌子("));\n});\n \n狼吞虎咽地吃.Task ('默认的', ['pack-js', 'pack-css ']);\n
\n\n

我们将输出管道输出到 牧师.清单() 第一个. 这将创建带有标记的文件,而不是我们之前使用的文件. 我们正在提供我们想要的路径 牧师-manifest.json和告诉 牧师.清单() 如果现有文件存在,则合并到现有文件. 然后我们告诉狼吞虎咽地吃将清单写入当前目录, 到那个时候,哪个是公共的/建设的. 路径问题是由于一个bug,在GitHub上有更详细的讨论.

\n\n

我们现在有了自动缩小、标记文件和清单文件. 所有这些都将使我们能够更快地将文件传递给用户, 只要我们做了修改,就会破坏他们的缓存. 不过,还剩下两个问题.

\n\n

第一个问题是,如果我们对源文件进行任何修改, 我们将获得新标记的文件, 但旧的也会留在那里. 我们需要一些方法来自动删除旧的缩小文件. 让我们使用一个允许我们删除文件的插件来解决这个问题:

\n\n
NPM install——save-dev del\n
\n\n

我们将在代码中需要它并定义两个新任务,一个用于每种类型的源文件:

\n\n
Var del = require('del');\n \n狼吞虎咽地吃.Task ('clean-js', function () {\n    返回德尔([\n        “公共/构建/ js / *.js'\n    ]);\n});\n \n狼吞虎咽地吃.任务('clean-css的,函数(){\n    返回德尔([\n        “公共/构建/ css / *.css的\n    ]);\n});\n
\n\n

然后,我们将确保新任务在我们的两个主要任务之前完成运行:

\n\n
狼吞虎咽地吃.任务('pack-js', ['clean-js'],函数(){\n狼吞虎咽地吃.任务('pack-css的, ['clean-css的],函数(){\n
\n\n

如果我们跑 狼吞虎咽地吃 同样,在此修改之后,我们将拥有最新的缩小文件.

\n\n

第二个问题是,我们不希望每次进行更改时都保持快速运行. 为了解决这个问题,我们需要定义一个观察者任务:

\n\n
狼吞虎咽地吃.Task ('watch', function() {\n 狼吞虎咽地吃.看(资产/ js / * * / *.js”,[' pack-js ']);\n 狼吞虎咽地吃.看(资产/ css / * * / *.css”,[' pack-css ']);\n});\n
\n\n

我们还将更改默认任务的定义:

\n\n
狼吞虎咽地吃.任务(“违约”,['看']);\n
\n\n

如果我们现在从命令行运行狼吞虎咽地吃, 我们将发现它在调用时不再构建任何东西. 这是因为它现在调用监视器任务,该任务将监视源文件的任何更改, 并且仅在检测到更改时进行构建. 如果我们尝试更改任何源文件,然后再次查看控制台,我们将看到 pack-jspack-css 任务与其依赖项一起自动运行.

\n\n

现在,我们要做的就是装载舱单.Json文件,并从中获取带标签的文件名. 我们如何做到这一点取决于我们特定的后端语言和技术堆栈, 实现起来也很简单, 所以我们就不详细讲了. 然而, 总体思路是,我们可以将清单加载到数组或对象中, 然后定义一个辅助函数,允许我们以类似于以下的方式从模板中调用版本化的资产:

\n\n
杯(包.js’)\n
\n\n

一旦我们这样做了, 我们再也不用担心文件名中的标签被更改了, 我们将能够专注于编写高质量的代码.

\n\n

本文的最终源代码以及一些样例资产可以在 这个GitHub存储库.

\n\n

结论

\n\n

在本文中,我们讨论了如何为构建过程实现基于狼吞虎咽地吃的自动化. 我希望这对您有所帮助,并允许您在自己的应用程序中开发更复杂的构建过程.

\n\n

请记住,狼吞虎咽地吃只是可用于此目的的工具之一, 还有很多其他的,比如Grunt, Browserify, 和Webpack. 它们的目的和解决问题的范围各不相同. 有些可以解决狼吞虎咽地吃无法解决的问题,比如捆绑 JavaScript 具有依赖关系的模块可以按需加载. 这被称为“代码分割”。, 相对于在每个页面上提供一个大文件并包含程序的所有部分的想法,这是一种改进. 这些工具相当复杂,但将来可能会涉及到. 在下面的文章中,我们将讨论如何自动部署应用程序.

\n","as":"div","isContentFit":true,"sharingWidget":{"url":"http://r0jm.wxzjnt.com/javascript/optimize-js-and-css-with-Gulp","title":"Simplify 前端 JS 和 CSS Optimization With 狼吞虎咽地吃","text":null,"providers":["linkedin","推特","脸谱网"],"gaCategory":null,"domain":{"name":"developers","title":"工程","vertical":{"name":"developers","title":"开发人员","publicUrl":"http://r0jm.wxzjnt.com/developers"},"publicUrl":"http://r0jm.wxzjnt.com/developers/blog"},"hashtags":"JavaScript,自动化,狼吞虎咽地吃,构建"}}