如何ant自定义任务Grunt任务

Grunt项目搭建 - 简书
下载简书移动应用
写了40540字,被35人关注,获得了18个喜欢
Grunt项目搭建
首先介绍一篇比较棒的文章:之后,我有必要改改自己的文章啦 /(ㄒoㄒ)/~~
安装时可能需要使用sudo(针对OSX、*nix、BSD等系统中)权限或者作为管理员(对于Windows环境)来执行以下命令。Grunt.js 0.4之后,其不再使用全局方式安装整个Grunt.js,而是在全局安装Grunt.js Client,然后在当前项目中安装Grunt,来避免未来不同项目对Grunt不同版本的依赖关系。如果安装了之前的版本,可以使用npm的命令来删除掉原来的Grunt.js。
npm uninstall -g grunt
然后安装:Grunt.js Client:
npm install -g grunt-cli
注意,安装grunt-cli并不等于安装了 Grunt!Grunt CLI的任务很简单:调用与Gruntfile在同一目录中 Grunt。这样带来的好处是,允许你在同一个系统上同时安装多个版本的 Grunt。
这样就能让多个版本的 Grunt 同时安装在同一台机器上。
package.json
"name": "my-project",
"version": "0.1.0",
"devDependencies": {
"grunt": "~0.4.1"
//或者“*”
"grunt-contrib-less": "*",
"grunt-contrib-watch": "*"
package.json是项目的配置文件,有一些项目的依赖信息,以及作者、版本等信息。我们先写一个简单的package.json。
name属性,表示该项的名字。
version属性,则是该项目的版本号。
devDependencies属性,则包含该项目的依赖,目前我们的依赖只有grunt,以及版本为0.4.1。
在终端大概包含该package.json的目录,输入命令:
npm install
会发现,该目录此时多了一个node_modules文件夹,里面有个grunt文件夹,这个就是我们安装在项目的Grunt.js。(表示只用less和watch)
写Gruntfile.js
module.exports = function(grunt) {
// 给grunt添加些设置
grunt.initConfig({
options: {
paths: ['less'],
compress: false,
//是否压缩
yuicompress: false, //是否压缩
optimization: 2
compile: {
expand: true,
cwd: 'less',
src: ['**/*.less'],
dest: 'css/',
//编译导出路径
ext: '.css'
files: ['less/*.less'],
tasks: ['less']
// 载入 "uglify" 插件任务
grunt.loadNpmTasks('grunt-contrib-less');
grunt.loadNpmTasks('grunt-contrib-watch');
// 定义默认需要执行的任务
grunt.registerTask('default', ['less', 'watch']);
拿一份现有的 Grunt 项目练手
假定Grunt CLI已经正确安装,并且已经有一份配置好package.json和 Gruntfile文件的项目了,接下来就很容易拿Grunt练手了:
将命令行的当前目录转到项目的根目录下。
执行npm install命令安装项目依赖的库。
执行 grunt命令。
OK,就是这么简单。还可以通过grunt --help命令列出所有已安装的Grunt任务(task),但是一般更建议去查看项目的文档以获取帮助信息。
package.json
"family": "dq",
"name": "dq-demo-static",
"version": "0.0.1",
"private": true,
"devDependencies": {
"grunt": "*",
"grunt-cmd-combo": "~1.0.0",
"grunt-contrib-less": "~0.9.0",
"grunt-contrib-uglify": "~0.2.2",
"grunt-contrib-watch": "*"
package.json
module.exports = function(grunt){
// 构建配置任务
grunt.initConfig({
//读取package.json的内容,形成个json数据
pkg: grunt.file.readJSON('package.json'),
// 指定子任务,调用可以是grunt copy(执行copy里面的全部任务),grunt copy:build(执行copy里面的build任务)
cwd: 'js',
//指向的目录是相对的,全称Change Working Directory更改工作目录
src: ['**'],
//指向源文件,**是一个通配符,用来匹配Grunt任何文件
dest: 'images', //用来输出结果任务
expand: true
//expand参数为true来启用动态扩展,涉及到多个文件处理需要开启
// 注:如果src: [ '**', '!**/*.styl' ],表示除去.styl文件,!在文件路径的开始处可以防止Grunt的匹配模式
src: ['css/**/*.*']
dynamic_mappings: {
expand: true,
// Enable dynamic expansion.
cwd: 'build/less',
// Src matches are relative to this path.
src: ['**/*.less', '!**/header.less', '!**/sidebar.less', '!**/footer.less', '!**/reset.less', '!**/layout.less', '!**/nprogress.less', '!**/post.less', '!**/single.less'], // Actual pattern(s) to match.
dest: 'css',
// Destination path prefix.
ext: '.css',
// Dest filepaths will have this extension.
// CSS压缩
expand: true,
cwd: 'css/',
src: ['*.css', '!*.min.css'],
dest: 'css/',
ext: '.css'
// 基本压缩(用于不常修改的文件)
expand: true,
cwd: 'build/js',
src: ['*.js', '!**/component.js', '!**/jquery.js', '!**/html5.js'],
dest: 'js/'
// public(常修改维护的文件)
publicJs: {
'js/public.js': ['build/js/public.js']
// 组件压缩(组件级别,一般仅压缩一次)
component: {
options: {
mangle: false
// false表示关闭短命名方式压缩。如果文件要共享到另一个项目中,会带来问题,因为名称已改变
'js/component.js': [ 'build/js/component/piano_storage.js']
// JS语法检查
all: ['js/*.js'],
// 监听(监测到文件改变时执行对应任务)
stylesheets: {
files: 'build/less/*.less',
tasks: [ 'stylesheets' ]
publicJs: {
files: 'build/js/public.js',
tasks: [ 'uglify:publicJs' ],
scripts: {
files: ['build/js/*.js', '!build/js/**/public.js' ],
tasks: [ 'uglify:build' ],
componentJS: {
files: ['build/js/component/*.js'],
tasks: [ 'uglify:component' ],
// initConfig结尾
// 加载任务-分开加载
grunt.loadNpmTasks("grunt-contrib-copy");
grunt.loadNpmTasks("grunt-contrib-less");
grunt.loadNpmTasks("grunt-contrib-jshint");
grunt.loadNpmTasks("grunt-contrib-uglify");
grunt.loadNpmTasks("grunt-contrib-watch");
grunt.loadNpmTasks("grunt-contrib-clean");
grunt.loadNpmTasks("grunt-contrib-cssmin");
// 把grunt-contrib插件全部一次性加载
// grunt.loadNpmTasks('grunt-contrib');
// grunt.event.on('watch', function(action, filepath) {
grunt.config(['uglify', 'build'], filepath);
grunt.event.on('watch', function(action, filepath) {
grunt.config(['jshint', 'all'], filepath);
// 自定义任务
// 作用:将以上众多子任务和在一起,便于手工运行或定义watch的任务
// 处理CSS
grunt.registerTask(
'stylesheets',
'Compiles the stylesheets.',
// [ 'less' ]
[ 'less', 'cssmin' ]
grunt.registerTask(
'scripts',
'Compiles the JavaScript files.',
[ 'uglify:publicJs' ]
// 处理public
grunt.registerTask(
'publicJs',
'Compiles the JavaScript files.',
[ 'uglify:publicJs' ]
// componentJS
grunt.registerTask(
'componentJS',
'Compiles the JavaScript files.',
[ 'uglify:componentJS' ]
// 创建工程
grunt.registerTask(
//任务名称
'Compiles all of the assets and copies the files to the build directory.',
//任务描述
[ 'clean', 'copy', 'stylesheets', 'scripts', 'jade' ]
//将要运行的任务数组,按顺序执行
// 默认工程
grunt.registerTask(
'default',
'Watches the project for changes, automatically builds them and runs a server.',
[ 'build', 'connect', 'watch' ]
// default任务运行build创建一个初始的build,然后它开始连接服务器,最后它会运行watch,监测文件变化和重新构建。
// 因为watch一直在运行,所以服务器一直在运行。在你的控制台上运行grunt,然后到http://localhost:4000查看你的项目。
//modules结尾
module.exports = function(grunt) {
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
expand: true,
cwd: 'script-ss/',
src: ['./page/*.js'],
dest: './script-min/',
ext: '.js'
expand: true,
cwd: 'script-min',
src: ['**/*.js'],
dest: 'script-min'
expand: true,
cwd: 'script-ss',
src: ['**/*.js'],
dest: 'script-min'
options: {
paths: ['less'],
compress: true,
yuicompress: true,
optimization: 2
compile: {
expand: true,
cwd: 'less',
src: ['**/*.less'],
dest: 'css/',
ext: '.css'
files: ['less/**/*.less'],
tasks: ['less'],
options: {
nospawn: true
files: ['script-ss/**/*.js'],
tasks: ['combo'],
options: {
spawn: false,
grunt.loadNpmTasks('grunt-cmd-combo');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-less')
grunt.loadNpmTasks('grunt-contrib-watch')
grunt.registerTask('default', ['watch']);
grunt.registerTask('mkcss', ['less']);
grunt.registerTask('normal', ['combo']);
grunt.registerTask('min', ['combo', 'uglify']);
grunt.registerTask('build', ['less', 'combo', 'uglify']);
html文件引入
&script src="script-min/page/tt.js" data-main="page/tt"&&/script&
define(function(require,exports){
var t2 = require('./t2')
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
打开微信“扫一扫”,打开网页后点击屏幕右上角分享按钮
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
选择支付方式:<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
您的访问请求被拒绝 403 Forbidden - ITeye技术社区
您的访问请求被拒绝
亲爱的会员,您的IP地址所在网段被ITeye拒绝服务,这可能是以下两种情况导致:
一、您所在的网段内有网络爬虫大量抓取ITeye网页,为保证其他人流畅的访问ITeye,该网段被ITeye拒绝
二、您通过某个代理服务器访问ITeye网站,该代理服务器被网络爬虫利用,大量抓取ITeye网页
请您点击按钮解除封锁&现在公认的JavaScript典型项目需要运行单元测试,合并压缩。有些还会使用代码生成器,代码样式检查或其他构建工具。
Grunt.js是一个开源工具,可以帮助你完成上面的所有步骤。它非常容易扩展,并使用JavaScript书写,所以任何为JavaScript库或项目工作的人都可以按自己的需要扩展它。
本文解释如何使用Grunt.js构建JavaScript库。Grunt.js依赖Node.js和npm,所以第一节解释其是什么,如何安装和使用。如果你对npm有了解,那你可以跳过这一节。第四和第五节讲述如何配置Grunt和一系列典型Grunt任务。
本文讨论的代码例子可以在上访问。
工具概述(Tool Chain Overview)
开始之前,我们需要三个工具:
Node.js是一个流行的服务器端JavaScript环境。它被用来编写和运行JavaScript服务和JavaScript命令行工具。如果你想进一步链接Node.js,你可以查看上相关的资料。
Npm是Node.js的包管理工具。它能从中心仓库下载依赖,解决大部分依赖冲突问题。Npm仓库仅仅存储Node.js服务器段和命令行项目。它不包含用于web和移动app相关的库。我们用它来下载Grunt.js。
Grunt.js是一个任务运行工具,我们用起构建我们的项目。它在Node.js之上运行并且通过Npm安装。
安装Node.js和Npm(Node.js and Npm Installation)
你可以直接从或用安装node.js。安装成功后在命令行输入 node -v Node.js将输出它的版本号。
大部分安装器和包管理工具将同时安装Npm。在命令行输入 npm -v 测试是否安装成功。如果成功将输出它的版本号。不同的系统可能安装方式略有不同。
下载和使用。
windows安装器包含npm并会添加path变量。仅在你下载Node.exe或从源代码编译Node是才需要独立安装Npm。从下载Npm的最新版zip压缩包。解压后赋值到Node.exe的安装目录。如果你愿意,你也可以放到任何位置,将其加入path变量即可。
安装包中内建Npm。
Npm基础(Npm Basics)
了解Npm基础操作对于使用和安装Grunt.js都有帮助。这节仅包含接触知识。更多细节可以查看。
本节将解释下面的东西:
什么是npm;
npm插件本地安装和全局安装的区别;
package.json文件和其规范;
npm安装命令。
概要(Overview)
Npm是一个包管理工具,可以从中心仓库下载和安装JavaScript依赖。安装包能被用在Node.js项目或命令行工具。
项目通常在package.json文件内部列出其依赖和安装插件。此外npm库也可以从命令行安装。
全局安装vs本地安装(Global vs Local Installation)
每个包可以安装在全局或本地环境。实际的区别是存储位置和访问方式。
全局安装包被直接存储在Node.js安装路径。他们之所以被称为全局,是因为他们可以在任何地方直接访问。
本地安装将下载包安装在当前工作路径。本地安装包只能从其所在目录访问。
本地安装包被存储进node_mudules子目录。无论你使用什么版本控制系统,你可以将其添加仅.ignorefile 文件。
Package.json
package.json文件包含npm项目描述。它总是位于项目的根目录,并且包含项目名称,版本,协议和其他类似元数据。最重要的是,它包含两个项目依赖列表。
&第一个列表包含运行所需要的依赖。任何希望使用此项目的人必须安装它们。第二个列表包含开发时需要依赖项。包括测试工具,构建工具和代码样式检测工具。
创建package.json最简单的方法是通过 npm install 命令。这条命令会以交互式提问一系列问题,并根据回答在当前工作目录生成基本的package.json文件。只有名字(name)和版本(version)属性是必须的。如果你不打算将你的库发布到Npm,你能忽略其余的部分。
下面的链接包含对package.json的详细描述:
安装命令(The Install Command)
Npm宝可以通过npm install 命令安装。默认安装到本地。全局安装需要指定 -g开关。
不带参数的 npm install 将在当前目录或上层目录查找 package.json 文件。如果发现,将会在当前目录安装所有列出的依赖项。
可以通过 npm install &pkg_name@version& 命令安装具体的npm包。这条命令将从中心仓库找到指定版本的包,并将其安装到当前目录。
版本号是可选的。如果省略将下载最新稳定版。
最后,通过 --sace-dev开关不仅可以安装包,还会将其添加到 package.json 的开发依赖中。
为项目添加Grunt.js(Adding Grunt.js to the Project)
我们将首先将Grunt.js添加进我们的JavaScript项目。为此我们需要安装两个Grunt.js模块:
grunt-cli&- 命令行接口 (CLI);
grunt&- 任务运行器.
提醒:最新的Grunt.js(4.0)不再兼容以前的版本。一些老的教程和文档不再适合新版Grunt.js了。
概论(Overview)
所有实际的工作是由任务运行器来做。命令行接口仅解析参数和将其传递个任务运行器。如果任务运行器没有安装将不会做任何事情。
命令行接口应该被安装在全局环境,然而任务运行器在本地环境。全局命令行接口保证Grunt命令可以在所有路径访问。任务运行器必须是本地的,因为不同的项目可能需要不同的Grunt版本。
安装(Installation)
安装全局Grunt命令行接口:
npm install -g grunt-cli
切换到项目根目录,通过npm init让Npm帮你生成package.json文件。它会问你些问题然后根据你的回答生成合法的package.json文件。只有名字和版本是必须的;你可以忽略其他选项。
将Grunt.js最新版添加到本地环境,同时添加到package.json文件的开发依赖里。
npm install grunt --save-dev
Package.json
通过前面的命令创建的package.json文件应该类似相面这样:
&name&: &gruntdemo&,
&version&: &0.0.0&,
&description&: &Demo project using grunt.js.&,
&main&: &src/gruntdemo.js&,
&scripts&: {
&test&: &echo \&Error: no test specified\& && exit 1&
&repository&: &&,
&author&: &Meri&,
&license&: &BSD&,
&devDependencies&: {
&grunt&: &~0.4.1&
配置Grunt.js(Configure Grunt.js)
Grunt.js运行任务并且通过任务完成工作。然而,Grunt.js安装成功后还没有任务可以使用。任务必须从插件载入,而插件通常需要Npm安装。
我们使用五个插件:
grunt-contrib-concat&- 拼接文件,
grunt-contrib-uglify&- 拼接并压缩文件(js),
grunt-contrib-copy&- 复制文件,
grunt-contrib-qunit&- 运行单元测试,
grunt-contrib-jshint&- 检查bug和JavaScript代码风格.
本节将解释如何配置这些插件。我们从最简单的配置开始,然后一步步解释如何配置任务。余下的子章节将详细讲解如何配置每个插件。
基础-不做任何配置(Basic Do Nothing Configuration)
Grunt将配置信息写到Gruntfile.js或Gruntfile.coffee文件里。由于我们创建的JavaScript项目,我们将使用JavaScript版本。最简单的Gruntfile.js看起来像下面这样:
//包装函数 有一个参数
module.exports = function(grunt) {
// 默认任务。在本例子中没有任何操作。
grunt.registerTask(&#39;default&#39;, []);
配置信息被保存在module.exports函数内部。它包含grunt对象作为其参数,并且通过调用该函数完成配置。
配置函数必须创建至少一个任务别名,并且配置他们。例如,上面的代码片段创建了一个“default”任务别名并且指定为空的任务列表。换句话说,默认的任务别名可以工作,但不会做任何事情。
用 grunt &taskAlias& 命令运行指定的 taskAlias任务。taskAlias的参数是可选的,如果省略,Grunt将使用“default”任务。
保存Gruntfile.js文件,在命令行运行Grunt:
你应该看到如下输出:
Done, without errors.
如果配置任务返回错误或警告Grunt将发出蜂鸣声(在命令行下输入错误的声音,译者未发现这点)。如果你不想听到蜂鸣声,你可以使用 -no-color 参数:
grunt -no-color
Grunt Npm 任务(Grunt Npm Tasks)
从插件添加任务是通过用步骤,对所有插件都是相同的。本节将概要讲述需要的过程,实际的例子将在下面的章节讲解。
安装插件(Install the Plugin)
首先,我们需要将插件添加进package.json文件的开发依赖里面,并且使用Npm进行安装:
npm install &plugin name& --save-dev
配置任务(Configure Tasks)
任务配置必须被存储在一个对象内部,有各自的任务名,并且被传递给 grunt.initConfig方法:
module.exports = function(grunt) {
grunt.initConfig({
firstTask : { /* ... 配置第一个任务 ... */ },
secondTask : { /* ... 配置第二个任务 ... */ },
// ... 其他任务 ...
lastTask : { /* ... 最后一个任务 ... */ }
// ... the rest ...
全面的任务配置信息解释看这里。本节仅描述最通用,简单的例子。假设任务接受一个文件列表,并处理他们,然后生出输出文件。
一个简单的任务配置例子:
firstTask: {
options: {
someOption: value //取决于插件
src: [&#39;src/file1.js&#39;, &#39;src/file2.js&#39;], //输入文件
dest: &#39;dist/output.js&#39; // 输出文件
例子中的任务配置有两个属性。一个是任务选项,名称必须是”options“。Grunt.js不会对options的属性执行任何操作,其行为有插件决定。
其他项可以有任何名字,并且要包含任务目标。最常见的任务是操作和生成文件,所以他们的target有两个属性,”src“ 和 ”dest“。src包含输入的文件列表,dest包含输出的文件名字。
如果你配置多个任务,Grunt将依次执行。下面的任务将运行两次,一次操作src及其子目录的所有js文件,另一次操作test及其子目录下的所有js文件:
multipleTargetsTask: {
target1: { src: [&#39;src/**/*.js&#39;] },
target2: { src: [&#39;test/**/*.js&#39;]] }
加载和注册任务(Load and Register Tasks)
最后,将插件载入必须使用 grunt.loadNpmTasks 函数,并且注册任务别名。
上面介绍的结构合起来如下:
module.exports = function(grunt) {
grunt.initConfig({ /* ... tasks configuration ... */ });
grunt.loadNpmTasks(&#39;grunt-plugin-name&#39;);
grunt.registerTask(&#39;default&#39;, [&#39;firstTask&#39;, &#39;secondTask&#39;, ...]);
配置JSHint(Configure JSHint)
检查JavaScript代码中潜在的问题和错误。他被设计成可配置的,并且有合理的默认值。
我们将使用
插件,grunt-contrib开头的插件都是有Grunt官方维护的,如果你创建自己的插件千万不要以次开头。
安装插件(Install the Plugin)
打开命令行,在项目根目录运行 npm install grunt-contrib-jshint --save-dev。将会添加插件到package.json文件的开发依赖,并且安装到本地Npm仓库。
JSHint参数(JSHint Options)
grunt-contrib-jshint插件的参数和JSHint一样。完整的参数列表可以访问。
JSHint 的参数 “eqeqeq” 会将 == 和 != 操作符报告为警告。默认是关闭的,因为这些操作符是合法的。但我建议你开启它,因为严格相等比非严格相等更安全。
同时我建议你开启trailing选项,将会对代码中结尾部的空白元素生成警告。结尾的空白在多行字符串中会引起奇怪的问题。
每一个可选项都是布尔值,设置为true将会开启相应检测。下面的例子开启了eqeqeq和trailing选项:
options: {
eqeqeq: true,
trailing: true
配置JSHint任务(Configure the JSHint Task)
grunt-contrib-jshint插件的任务名字是“jshint”。我们将使用上一节中的配置选项,使它检测位于src和test目录下的全部JavaScript文件。
JSHint的配置信息必须写在名为“jshint”的属性内部。可以有两个属性,一个数参数(options)另一个是目标(target)。
目标可以在任何属性内部,在这里我们仅使用“target”。其必须包含待验证的JavaScript文件列表。文件列表可以放在目标的src属性中,可以使用**和*通配符。
有两个自定义选项,将会验证位于src和test目录及其子目录下的所有js文件。
grunt.initConfig({
options: {
eqeqeq: true,
trailing: true
src : [&#39;src/**/*.js&#39;, &#39;test/**/*.js&#39;]
加载和注册(Load and Register)
最后需要载入和注册 grunt-contrib-jshint 任务:
grunt.loadNpmTasks(&#39;grunt-contrib-jshint&#39;);
grunt.registerTask(&#39;default&#39;, [&#39;jshint&#39;]);
全部JSHint配置选项(Full JSHint Configuration)
目前为止完整的 Gruntfile.js 文件如下:
module.exports = function(grunt) {
grunt.initConfig({
options: {
trailing: true,
eqeqeq: true
src : [&#39;src/**/*.js&#39;, &#39;test/**/*.js&#39;]
grunt.loadNpmTasks(&#39;grunt-contrib-jshint&#39;);
grunt.registerTask(&#39;default&#39;, [&#39;jshint&#39;]);
拼接文件(Concatenate Files)
js文件一般是分散的(如果你的项目不是几十行js的话),上线前我们必须将其打包进一个文件,并添加版本号和项目名字。在文件的开始位置应该包含库名称,版本,协议,构建时间和其他一些信息。
例如,像下面这样:
/*! gruntdemo v1.0.2 -
License: BSD */
var gruntdemo = function() {
我们将使用
插件完成拼接任务,并生成正确的注释信息。
安装插件(Install the Plugin)
和前面一样,将插件写进package.json文件的开发依赖里,然后从Npm仓库安装到本地。
打开命令行,运行如下命令:
npm install grunt-contrib-concat --save-dev
加载Package.json(Load Package.json)
首先从package.json文件加载配置信息,并存储在pkg属性。需要使用 grunt.file.readJSON 函数:
pkg: grunt.file.readJSON(&#39;package.json&#39;),
现在pkg的值是一个对象,包含全部package.json的信息。项目名被存储在pkg.name属性,版本被存储在pkg.version。版权被存储在pkg.license属性等等。
生成页头信息和 文件名(Compose Banner and File Name)
Grunt提供一套,我们可以使用它构建页头和文件名称。模版可以在字符串中嵌入JavaScript表达式,通过&%= expression %& 语法。Grunt计算表达式的值并替换模版中的表达式。
例如,模版中的 &%= pkg.name %& 将被替换为 pkg.name 的属性值。如果属性值是字符串,模版的行为类似字符串拼接 ...&#39; + pkg.name + &#39;...
模版中可以引用Grunt中的全部属性。系统提供了一个非常有帮助的日期格式化函数。我们将使用 grunt.template.today(format) 函数生成当前的时间戳。
让我们生成一个简单的页头,包含项目名称,版本号,版权和当前的日期。由于我们需要在 Uglify 任务中使用banner,所以我们将其存储在变量中:
var bannerContent = &#39;/*! &%= pkg.name %& v&%= pkg.version %& - &#39; +
&#39;&%= grunt.template.today(&yyyy-mm-dd&) %& \n&#39; +
License: &%= pkg.license %& */\n&#39;;
上面的模版生成如下的页头:
/*! gruntdemo v0.0.1 -
License: BSD */
项目的名称和版本部分也需要在多处使用。将项目名和版本号拼在一起,存储在一个变量中:
var name = &#39;&%= pkg.name %&-v&%= pkg.version%&&#39;;
生成的名字如下:
gruntdemo-v0.0.1
配置目标和选项(Configure Target and Options)
target必须包含需要被拼接的文件列表,和合并完成后输出文件的名字。target支持通配符和模版,所以我们使用前一节生成的模版:
target : {
// 拼接src目录下的所有文件
src : [&#39;src/**/*.js&#39;],
// place the result into the dist directory,
// name variable contains template prepared in
// previous section
dest : &#39;distrib/&#39; + name + &#39;.js&#39;
concat插件也可以通过banner属性添加banner。由于上面我们已经将banner内容赋给bannerContent变量,所以我们仅需引入即可:
options: {
banner: bannerContent
加载和注册(Load and Register)
最后不要忘记从Npm加载 grunt-contrib-concat ,并且将其注册到默认工作流:
grunt.loadNpmTasks(&#39;grunt-contrib-concat&#39;);
grunt.registerTask(&#39;default&#39;, [&#39;jshint&#39;, &#39;concat&#39;]);
完整的拼接配置(Full Concat Configuration)
这一节出示包含完整contat配置的Gruntfile.js文件。
注意pkg属性在传递给initConfig方法的参数中定义。我们不能把他放在其他地方,因为它读取模版信息,并且仅在initConfig方法的参数和grunt对象中有访问模版的权限。
module.exports = function(grunt) {
var bannerContent = &#39;... banner template ...&#39;;
var name = &#39;&%= pkg.name %&-v&%= pkg.version%&&#39;;
grunt.initConfig({
// pkg is used from templates and therefore
// MUST be defined inside initConfig object
pkg : grunt.file.readJSON(&#39;package.json&#39;),
// concat configuration
options: {
banner: bannerContent
target : {
src : [&#39;src/**/*.js&#39;],
dest : &#39;distrib/&#39; + name + &#39;.js&#39;
jshint: { /* ... jshint configuration ... */ }
grunt.loadNpmTasks(&#39;grunt-contrib-jshint&#39;);
grunt.loadNpmTasks(&#39;grunt-contrib-concat&#39;);
grunt.registerTask(&#39;default&#39;, [&#39;jshint&#39;, &#39;concat&#39;]);
压缩(Minify)
如果浏览器载入和解析大文件,会使页面载入变得缓慢。可能不是所有项目都会遇到这个问题,但对于移动端的app和使用非常多大型库的大型web应用程序而言,是必须要考虑的。
因此,我们也将我们库进行压缩。压缩会将输入的文件变小,通过去除空白元素,注释,替换变量名称等,但不会改变代码逻辑。
压缩功能使用
插件,其通过Grunt集成 。它通过uglify任务拼接和压缩一组文件。
源程序映射(Source Maps)
压缩会使生成的文件难于阅读和调试,所以我们通过生成源程序映射来简化问题。
源程序映射是压缩文件和源文件之间的纽带。如果浏览器支持,浏览器调试工具会显示对人友好的源文件,而不是压缩文件。仅有chrome和nightly版本的 firefox支持源代码映射。你可以在 和 上获取更多信息,我建议你看看阮一峰老师的这篇文章:/blog/2013/01/javascript_source_map.html
安装插件(Install the Plugin)
将插件添加到package.json的开发依赖里,并且安装到本地Npm仓库。
使用如下命令:
npm install grunt-contrib-uglify --save-dev
配置目标(Configure Target)
配置uglify任务目标的方式和concat任务类似。必须要包含待压缩的javascript文件列表和输出文件的名字。
支持通配符和模版,所以我们可以使用前面章节中的用到的模版:
target : {
// use all files in src directory
src : [&#39;src/**/*.js&#39;],
// place the result into the dist directory,
// name variable contains template prepared in
// previous sub-chapter
dest : &#39;distrib/&#39; + name + &#39;.min.js&#39;
配置选项(Configure Options)
配置banner的方式和concat一样&&通过设置“banner”属性并且支持模版。因此,我们可以重复使用前面章节中准备好的 bannerContent 变量。
通过“sourceMap”属性生成源文件映射。包含生成文件的名字。此外,必须设置“sourceMapUrl”和“sourceMapRoot”属性。前一个包含相对于uglified文件到源文件映射文件的路径,后一个包含是源文件映射到源文件的相对路径。
通过bannerContent变量生成页眉,通过name变量生成源文件映射文件的名字:
options: {
banner: bannerContent,
sourceMapRoot: &#39;../&#39;,
sourceMap: &#39;distrib/&#39;+name+&#39;.min.js.map&#39;,
sourceMapUrl: name+&#39;.min.js.map&#39;
加载和注册(Load and Register)
最后一步是从Npm加载 grunt-contrib-uglify,并且添加到默认任务列表:
grunt.loadNpmTasks(&#39;grunt-contrib-uglify&#39;);
grunt.registerTask(&#39;default&#39;, [&#39;jshint&#39;, &#39;concat&#39;, &#39;uglify&#39;]);
全部 Uglify 配置信息(Full Uglify Configuration)
下面是包含完整uglify配置信息的Gruntfile.js文件:
module.exports = function(grunt) {
var bannerContent = &#39;... banner template ...&#39;;
var name = &#39;&%= pkg.name %&-v&%= pkg.version%&&#39;;
grunt.initConfig({
// pkg must be defined inside initConfig object
pkg : grunt.file.readJSON(&#39;package.json&#39;),
// uglify configuration
options: {
banner: bannerContent,
sourceMapRoot: &#39;../&#39;,
sourceMap: &#39;distrib/&#39;+name+&#39;.min.js.map&#39;,
sourceMapUrl: name+&#39;.min.js.map&#39;
target : {
src : [&#39;src/**/*.js&#39;],
dest : &#39;distrib/&#39; + name + &#39;.min.js&#39;
concat: { /* ... concat configuration ... */ },
jshint: { /* ... jshint configuration ... */ }
grunt.loadNpmTasks(&#39;grunt-contrib-jshint&#39;);
grunt.loadNpmTasks(&#39;grunt-contrib-concat&#39;);
grunt.loadNpmTasks(&#39;grunt-contrib-uglify&#39;);
grunt.registerTask(&#39;default&#39;, [&#39;jshint&#39;, &#39;concat&#39;, &#39;uglify&#39;]);
最后的发布文件(Latest Release File)
最后要发布的库包括两个文件,并且都在名字中含有版本号。这会给想要自动下载每个新版本的人造成不必要的困难。
如果想要查看是否发布了新版本和新版本的名字,必须每次都要获取和解析一个json文件。如果每次都更改名称,则必须更新下载脚本。
因此我们将使用
插件创建无版本号的文件。
安装插件(Install the Plugin)
将插件添加进package.json的开发依赖,并且从Npm仓库安装到本地。
使用如下命令:
npm install grunt-contrib-copy --save-dev
配置插件(Configure the Plugin)
copy配置信息包括三个目标,分别对应三个发布文件。没有配置选项,基本和前一个插件配置过程一样。
仅有一点不一样,就是多任务。每个任务包含一对 src/dest,待拷贝的名字和待创建的名字。
对前面的任务配置选项稍加修改。将所有文件名字放到变量中,以便可以重复使用:
module.exports = function(grunt) {
/* define filenames */
latest = &#39;&%= pkg.name %&&#39;;
name = &#39;&%= pkg.name %&-v&%= pkg.version%&&#39;;
devRelease = &#39;distrib/&#39;+name+&#39;.js&#39;;
minRelease = &#39;distrib/&#39;+name+&#39;.min.js&#39;;
sourceMapMin = &#39;distrib/source-map-&#39;+name+&#39;.min.js&#39;;
lDevRelease = &#39;distrib/&#39;+latest+&#39;.js&#39;;
lMinRelease = &#39;distrib/&#39;+latest+&#39;.min.js&#39;;
lSourceMapMin = &#39;distrib/source-map-&#39;+latest+&#39;.min.js&#39;;
grunt.initConfig({
development: { // copy non-minified release file
src: devRelease,
dest: lDevRelease
minified: { // copy minified release file
src: minRelease,
dest: lMinRelease
smMinified: { // source map of minified release file
src: sourceMapMin,
dest: lSourceMapMin
uglify: { /* ... uglify configuration ... */ },
concat: { /* ... concat configuration ... */ },
jshint: { /* ... jshint configuration ... */ }
grunt.loadNpmTasks(&#39;grunt-contrib-jshint&#39;);
grunt.loadNpmTasks(&#39;grunt-contrib-concat&#39;);
grunt.loadNpmTasks(&#39;grunt-contrib-uglify&#39;);
grunt.loadNpmTasks(&#39;grunt-contrib-copy&#39;);
grunt.registerTask(&#39;default&#39;, [&#39;jshint&#39;, &#39;concat&#39;, &#39;uglify&#39;, &#39;copy&#39;]);
单元测试(Unit Tests)
最后,配置 grunt.js 运行单元测试,测试最新发布的文件。我们将使用 grunt-contrib-qunit 插件实现目标。这个插件将在无头的 实例中运行 单元测试。
这个解决方案不能模拟不同浏览器和查找全部 bug,但对于我们来说已经足够了。如果想得到更好的配置,可以使用 js-test-driver 或 其他类似工具,然而,关于
的配置超出了本文的范围。
准备测试用例(Prepare Tests)
Qunit 单元测试经常要运行 src 目录里的 JavaScript 文件,由于测试是开发的一部分。如果你想测试刚刚发布的拼接压缩后的版本工作状况,需要创建一个新的 QUnit HTML 文件,并加载最后发布的文件。
下面是一个例子是 Qunit 的入口文件:
&!DOCTYPE html&
&meta charset=&utf-8&&
&title&QUnit Example&/title&
&link rel=&stylesheet& href=&../libs/qunit/qunit.css&&
&div id=&qunit&&&/div&
&div id=&qunit-fixture&&&/div&
&script src=&../libs/qunit/qunit.js&&&/script&
&!-- Use latest versionless copy of current release --&
&script src=&../distrib/gruntdemo.min.js&&&/script&
&script src=&tests.js&&&/script&
安装插件(Install the Plugin)
将插件添加进package.json 的开发者依赖中,并且将其安装到本地 Npm 仓库。
使用如下命令:
npm install grunt-contrib-qunit --save-dev
配置插件(Configure Plugin)
配置 grunt-contrib-qunit 插件和配置前面的任务如出一辙。由于我们使用默认的 Qunit 配置,所以可以省略选项属性。不能忽略的是必须配置 target,指定全部的 Qunit HTML 文件。
接下来指定位于测试目录下的全部 HTML 文件,及其子目录应该运行 Qunit 测试:
grunt.initConfig({
src: [&#39;test/**/*.html&#39;]
// ... all previous tasks ...
完整的 Grunt.js 文件(Final Grunt.js File)
下面是完整的 Gruntfile.js 配置信息:
module.exports = function(grunt) {
var name, latest, bannerContent, devRelease, minRelease,
sourceMap, sourceMapUrl, lDevRelease, lMinRelease,
lSourceMapM
latest = &#39;&%= pkg.name %&&#39;;
name = &#39;&%= pkg.name %&-v&%= pkg.version%&&#39;;
bannerContent = &#39;/*! &%= pkg.name %& v&%= pkg.version %& - &#39; +
&#39;&%= grunt.template.today(&yyyy-mm-dd&) %& \n&#39; +
License: &%= pkg.license %& */\n&#39;;
devRelease = &#39;distrib/&#39;+name+&#39;.js&#39;;
minRelease = &#39;distrib/&#39;+name+&#39;.min.js&#39;;
sourceMapMin = &#39;distrib/&#39;+name+&#39;.min.js.map&#39;;
sourceMapUrl = name+&#39;.min.js.map&#39;;
lDevRelease = &#39;distrib/&#39;+latest+&#39;.js&#39;;
lMinRelease = &#39;distrib/&#39;+latest+&#39;.min.js&#39;;
lSourceMapMin = &#39;distrib/&#39;+latest+&#39;.min.js.map&#39;;
grunt.initConfig({
pkg: grunt.file.readJSON(&#39;package.json&#39;),
src: [&#39;test/**/*.html&#39;]
// configure copy task
development: {
src: devRelease,
dest: lDevRelease
minified: {
src: minRelease,
dest: lMinRelease
smMinified: {
src: sourceMapMin,
dest: lSourceMapMin
// configure uglify task
options: {
banner: bannerContent,
sourceMapRoot: &#39;../&#39;,
sourceMap: sourceMapMin,
sourceMappingURL: sourceMapUrl
src: [&#39;src/**/*.js&#39;],
dest: minRelease
// configure concat task
options: {
banner: bannerContent
src: [&#39;src/**/*.js&#39;],
dest: devRelease
// configure jshint task
options: {
trailing: true,
eqeqeq: true
src: [&#39;src/**/*.js&#39;, &#39;test/**/*.js&#39;]
grunt.loadNpmTasks(&#39;grunt-contrib-jshint&#39;);
grunt.loadNpmTasks(&#39;grunt-contrib-concat&#39;);
grunt.loadNpmTasks(&#39;grunt-contrib-uglify&#39;);
grunt.loadNpmTasks(&#39;grunt-contrib-copy&#39;);
grunt.loadNpmTasks(&#39;grunt-contrib-qunit&#39;);
grunt.registerTask(&#39;default&#39;, [&#39;jshint&#39;, &#39;concat&#39;, &#39;uglify&#39;, &#39;copy&#39;, &#39;qunit&#39;]);
结论(Conclusion)
现在 Grunt.js 配置好了,并且可以使用了。我们的目标是使配置尽可能简单,使用成对的 src/dest,通配符和模版。当然,Grunt.js 也提供其他更。
如果能够自动下载和管理项目依赖的库,会变得更美好。我发现两个可行的解决方案, 和 。我没有试过他们,但都可以管理前端JavaScript包和其依赖。
文章有些长,拖了很久的文章终于翻译完成了,我最近打算写一本关于 Grunt 指南的书籍,会详细讲解如何构建一套前端自动化工具,如果你支持我的工作,那就给我捐助吧。
英文:http://flippinawesome.org//building-a-javascript-library-with-grunt-js/
文章不错...正学习之....
关于“grunt-contrib-jshint插件的任务名字是“jshint””,我有个疑问。
插件名和任务名之间的关联规则是什么?官方有明确吗?

我要回帖

更多关于 战争雷霆自定义任务 的文章

 

随机推荐