打包的目的和意义就不用叙述了直接上干货

http://www.gruntjs.net/getting-started里面的教程也太简单了,需要下一番功夫去研究才行。本文将grunt打包的常用方法都用实例描述,更加清晰易懂。

1.    第一个简单的grunt打包


1)需要安装nodejs:http://www.cnblogs.com/chuaWeb/p/nodejs-npm.html

  本人的nodejs工程目录为F:\chuaNodejs(后续所有相对路径都是相对于这个目录)

2)命令行到nodejs目录(需要系统管理员权限,不然后续过程中会报错)执行npm install -g grunt-cli

3)在nodejs工程目录下建一个package.json,内容为

{
"name": "my-first-grunt",
"file": "jquery",
"version": "0.1.0",
"devDependencies": {
"grunt": "~0.4.5",
"grunt-contrib-jshint": "~0.10.0",
"grunt-contrib-nodeunit": "~0.4.1",
"grunt-contrib-uglify": "~0.5.0"
}
}

  其中file属性在Gruntfile.js中要用到的属性,打包源名称

  然后将devDependencies下面的包给下载下来,比如下载grunt: npm install grunt --save-dev 其他包下载方式一样

  需要注意的是package.json中的数据必须是严格的json数据格式(连添加注释都是不可以的)。

4) 在nodejs工程目录下建一个Gruntfile.js,内容为

 module.exports = function (grunt) {
// 项目配置
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),//获取解析package.json将内容保存在pkg中
uglify: {
options: {
banner: '/*! <%= pkg.file %> <%= grunt.template.today("yyyy-mm-dd") %> */\n'
},
build: {
src: 'src/<%=pkg.file %>.js',
dest: 'dest/<%= pkg.file %>.min.js'
}
}
});
// 加载提供"uglify"任务的插件
grunt.loadNpmTasks('grunt-contrib-uglify');
// 默认任务
grunt.registerTask('default', ['uglify']);
}

  里面pkg读取package.json文件,然后可以访问其内容中的属性,如pkg.file。build属性src是待压缩的文件,dest是压缩重定向到该文件。

  所以现在我要建立一个src目录,目录下面保存了一个叫做jquery.js的文件

5)命令行运行:grunt

  输出

Running “uglify:build” (uglify) task
File dest/jquery.min.js created: 277.14 kB ->93.35 kB
>> 1 file created.
Done.

  创建了dest/jquery.min.js

  

  注意:grunt命令和grunt uglify等价。当然也可以带上任务名称default:grunt default能等到同样结果。

6)总结:

  grunt.initConfig:

  为当前项目初始化一个配置对象,其中传入的 configObject 参数可以用在后续的task中,可以通过grunt.config 方法访问。几乎每个项目的 Gruntfile 都会调用此方法。

  注意,任何 <% %> 模板字符串只会在取到配置数据后才被处理。

  不同的插件有各自的参数,比如例子中的uglify插件用到的参数有options和build。详细信息需要参考各个插件。

  initConfig详情参考:http://www.gruntjs.net/api/grunt.config#grunt.config.init

  grunt.loadNpmTasks:

  grunt打包主要是用到各种插件,比如上面的压缩用的插件uglify。加载插件需要使用该方法。

  从指定的 Grunt 插件中加载任务。此插件必须通过npm安装到本地,并且是参照 Gruntfile.js 文件的相对路径。

  详情参考:http://www.gruntjs.net/api/grunt.task#grunt.task.loadnpmtasks

  grunt.registerTask:

  注册 "别名任务" 或 任务函数。此方法支持以下两种类型:

  别名任务(如果指定了一个任务列表,那么,新注册的任务将会是这一个或多个任务的别名(alias)。当此"别名任务"执行时,taskList中的所有任务都将按指定的顺序依次执行。taskList 参数必须是一个任务数组。):grunt.task.registerTask(taskName, taskList)

  上面的例子就是别名任务。定义一个"default" 任务,当执行 Grunt 且不通过参数指定任务时,第二个参数中的任务将依序执行

  任务函数(如果传入description和taskFunction,每当任务运行时,指定的函数(taskFunction)都会被执行。此外,当执行 grunt --help时,前面指定的描述(description)就会显示出来。特定任务的属性和方法在任务函数内部通过this对象的属性即可访问。如果任务函数返回false表示任务失败。):grunt.task.registerTask(taskName, description, taskFunction)

  下一个例子我们就试一下这个任务函数,现在刚才例子每一个步骤目的就清晰了。

  详情参考:http://www.gruntjs.net/api/grunt.task#grunt.task.registertask

2. 使用任务函数方式实现刚才的那个打包。


  其他的东西都没有变,Gruntfile.js变成了

 module.exports = function (grunt) {
// 加载提供"uglify"任务的插件
grunt.loadNpmTasks('grunt-contrib-uglify');
// 任务函数
grunt.registerTask('build', 'uglify 使用 任务函数版', function () {
//任务列表
var tasks = ['uglify'];
// 项目配置
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),//获取解析package.json将内容保存在pkg中
});
var uglifyTask = {
options: {
banner: '/*! <%= pkg.file %> <%= grunt.template.today("yyyy-mm-dd") %> */\n'
},
build: {
src: 'src/<%=pkg.file %>.js',
dest: 'dest/<%= pkg.file %>.min.js'
}
}
//将一个或多个任务放入队列中
grunt.task.run(tasks);
//给当前项目的 Grunt 配置中的uglify属性设置一个值。
grunt.config.set("uglify", uglifyTask);
});
}

  然后去命令行运行: grunt bulid

  和第一个不同的是运行命令必须带上了任务名称build。

  注意前面提到的任何 <% %> 模板字符串只会在取到配置数据后才被处理。

3. 合并压缩


  有些时候为了减少请求需要合并多个文件,且需要压缩。使用uglify即可做到这一点。

  Gruntfile.js代码

 module.exports = function (grunt) {
// 项目配置
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),//获取解析package.json将内容保存在pkg中
uglify: {
options: {
banner: '/*! <%= pkg.file %> <%= grunt.template.today("yyyy-mm-dd") %> */\n',//压缩目标文件头部注释
mangle: false//变量和函数名称不压缩
},
my_target: {//该对象名称随意
files: {
'dest/libs.min.js': ['src/jquery.js', 'src/router.js']
}
}
}
});
// 加载提供"uglify"任务的插件
grunt.loadNpmTasks('grunt-contrib-uglify');
// 默认任务
grunt.registerTask('default', ['uglify']);
}

  文件压缩的顺序按照files中定义的数组的顺序压缩。我们可以通过options.mangle来设置变量和函数名称是否压缩。还可以有下面的用法

 options: {
banner: '/*! <%= pkg.file %> <%= grunt.template.today("yyyy-mm-dd") %> */\n',//压缩目标文件头部注释
mangle: {
except: ["jQuery"]//不压缩的关键字列表
}
}

  最终jquery.js和router.js合并压缩成libs.min.js

  详情参考:https://www.npmjs.com/package/grunt-contrib-uglify

4. 合并压缩require配置的文件。


  首先需要下载grunt-contrib-requirejs插件:npm install grunt-contrib-requirejs --save-dev

  比如我们的执行文件main.js使用的是require来模块化加载,代码如下

 require.config({
baseUrl: "",
paths: {
"jquery": "src/jquery",
"bootstrap": "src/bootstrap.min",
"validator": "src/bootstrapValidator.min"
},
shim: {
"bootstrap":["jquery"],
"beyond": ["bootstrap"],
"validator": ["bootstrap"]
}
});
requirejs(['validator'], function (v) {
//代码
});

  我们希望jquery/bootstrap/validator几个文件合并成一个,避免多次请求。

  我们新建一个grunt配置文件gruntCfg.json将main.js的require文件配置代码段拷贝到这个配置文件。并写入输入输出目标。源码如下

 {
"requirejs": {
"main": {
"options": {
"baseUrl": "",
"paths": {
"jquery": "src/jquery",
"bootstrap": "src/bootstrap.min",
"validator": "src/bootstrapValidator.min"
},
"shim": {
"bootstrap":["jquery"],
"validator": ["bootstrap"]
},
"include":["validator","jquery","bootstrap"],
"out":"dest/libs.js"
}
}
}
}

  上面include中我打乱了顺序,为了测试压缩顺序我在三个库的前面都添加了console.log(“我是” + 模块名称)。

  修改Gruntfile.js

 module.exports = function (grunt) {
grunt.loadNpmTasks('grunt-contrib-requirejs');
//为了介绍自定义任务搞了一个这个
grunt.registerTask('build', 'require', function () { //设置requireJs的信息
var taskCfg = grunt.file.readJSON('gruntCfg.json');
var requireTask = taskCfg.requirejs; //添加人任务列表
grunt.task.run(['requirejs']);
grunt.config.set("requirejs", requireTask);
});
}

  好了现在看一下相关文件的文件结构如下

  

  执行build任务:grunt build

  文件夹dest下多了一个libs.js文件

  

  打开来看

  

  第一行代码就有我刚才添加的console。继续找我添加的标志的话发现压缩顺序是:jQuery->bootstrap->bootstrapValidator。和我们的shim依赖顺序一致。说明合并压缩的顺序没有问题。

  更多详情请查看:https://www.npmjs.com/package/grunt-contrib-requirejs

5. 多任务


  我们先看一下使用别名任务来执行多个任务的情况,Gruntfile.js源码如下

 module.exports = function (grunt) {
// 项目配置
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),//获取解析package.json将内容保存在pkg中
uglify: {
options: {
banner: '/*! <%= pkg.file %> <%= grunt.template.today("yyyy-mm-dd") %> */\n'
},
build: {
src: 'src/<%=pkg.file %>.js',
dest: 'dest/<%= pkg.file %>.min.js'
},
my_target1: {
files: {
'dest/libs.min.js': ['src/jquery.js', 'src/router.js']
}
},
my_target2: {
files: {
'dest/libs.min2.js': ['src/jquery.js', 'src/router.js']
}
}
},
requirejs: {
"main": {
"options": {
"baseUrl": "",
"paths": {
"jquery": "src/jquery",
"bootstrap": "src/bootstrap.min",
"validator": "src/bootstrapValidator.min"
},
"shim": {
"bootstrap":["jquery"],
"validator": ["bootstrap"]
},
"include":["validator","jquery","bootstrap"],
"out":"dest/libs.js"
}
},
"main2": {
"options": {
"baseUrl": "",
"paths": {
"jquery": "src/jquery",
"bootstrap": "src/bootstrap.min",
"validator": "src/bootstrapValidator.min"
},
"shim": {
"bootstrap":["jquery"],
"validator": ["bootstrap"]
},
"include":["validator","jquery","bootstrap"],
"out":"dest/libs2.js"
}
}
} });
// 加载提供"uglify"任务的插件
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-requirejs');
// 默认任务
grunt.registerTask('default', ['uglify',"requirejs"]);
}

  执行:grunt

  dest文件夹下多出了5个文件

  

  源码解析是:任务列表有两个任务'uglify'和"requirejs",'uglify'有三个子任务:build/ my_target1/ my_target2, "requirejs"有两个子任务main/main2。最终这五个子任务完成后生成的结果就是dest下多出的5个文件。

  还可以使用任务函数方式注册多个任务。Gruntfile.js源码如下

 module.exports = function (grunt) {
grunt.initConfig({
log: {
l1: [1,2,3],
l2: 'hello world',
l3: false,
l4: {name: "chua"},
l5: 1,
//这个是不行的l6: undefined,
//这个是不行的l7: null
l8: function(){alert("test")}
}
}); grunt.registerMultiTask('log','log stuff.', function(){
grunt.log.writeln(this.target + ': ' + this.data);
});
}

  执行:grunt log

  

  我们使用自定义方式实现先前的多任务Gruntfile.js源码如下

 module.exports = function (grunt) {
// 项目配置
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),//获取解析package.json将内容保存在pkg中
log: {
uglify: {
options: {
banner: '/*! <%= pkg.file %> <%= grunt.template.today("yyyy-mm-dd") %> */\n'
},
build: {
src: 'src/<%=pkg.file %>.js',
dest: 'dest/<%= pkg.file %>.min.js'
},
my_target1: {
files: {
'dest/libs.min.js': ['src/jquery.js', 'src/router.js']
}
},
my_target2: {
files: {
'dest/libs.min2.js': ['src/jquery.js', 'src/router.js']
}
}
},
requirejs: {
"main": {
"options": {
"baseUrl": "",
"paths": {
"jquery": "src/jquery",
"bootstrap": "src/bootstrap.min",
"validator": "src/bootstrapValidator.min"
},
"shim": {
"bootstrap":["jquery"],
"validator": ["bootstrap"]
},
"include":["validator","jquery","bootstrap"],
"out":"dest/libs.js"
}
},
"main2": {
"options": {
"baseUrl": "",
"paths": {
"jquery": "src/jquery",
"bootstrap": "src/bootstrap.min",
"validator": "src/bootstrapValidator.min"
},
"shim": {
"bootstrap":["jquery"],
"validator": ["bootstrap"]
},
"include":["validator","jquery","bootstrap"],
"out":"dest/libs2.js"
}
}
}
}
});
// 加载提供"uglify"任务的插件
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-requirejs'); grunt.registerMultiTask('log','log stuff.', function(){
if(this.target == "uglify"){
//添加人任务列表
grunt.task.run(['uglify']);
grunt.config.set("uglify", this.data);
}else if(this.target == "requirejs"){
//添加人任务列表
grunt.task.run(['requirejs']);
grunt.config.set("requirejs", this.data);
}
});
}

  执行:grunt log

  照样得到先前的结果

  

  说到底和先前的别名任务没有什么不同。

6. 压缩整个文件夹下的js文件


  压缩src下的所有js文件,Gruntfile.js源码

 module.exports = function (grunt) {
grunt.initConfig({
uglify: {
my_target: {
files: [{
expand: true,
cwd: 'src',
src: '**/*.js',
dest: 'dest'
}]
}
}
});
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.registerTask('default', ['uglify']);
}

  源码文件结构(注意src/router下面还有一个js文件)

  

  执行:grunt

  目标文件结构

  

  所以这个方法还是比较方便的,他会遍历源文件夹下的所有文件(包括子文件夹)然后压缩。

  刚才上面的方式没有拷贝src文件夹,下面这种方式拷贝了src文件夹

 module.exports = function (grunt) {
grunt.initConfig({
uglify: {
my_target: {
files: [{
expand: true,
//cwd: 'src',
src: 'src/**/*.js',
dest: 'dest'
}]
}
}
});
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.registerTask('default', ['uglify']);
}

  执行:grunt

  目标文件结构变成

  

  src下所有的js都被压缩并保持原来的目录结构。

7. grunt-contrib-requirejs插件的更详细使用


  我们用实例来说明。现在我们的文件结构是这样子的

  

  main.js是我们使用require的真实配置文件,源码如下

 require.config({
baseUrl: "",
paths: {
"jquery": "src/jquery",
"bootstrap": "src/bootstrap.min",
"validator": "src/bootstrapValidator.min"
},
shim: {
"bootstrap":["jquery"],
"beyond": ["bootstrap"],
"validator": ["bootstrap"]
}
});
requirejs(['validator'], function (v) {
//代码
});

  Gruntfile.js的源码

 module.exports = function (grunt) {
grunt.initConfig({
"requirejs": {
"main": {
"options": {
"baseUrl": ".",
"mainConfigFile": "main.js",//指定配置文件
"name": "test",//会将对应的文件压缩到main.js依赖的文件的前面压缩。但是会在main.js非依赖文件后面压缩(比如router.js)
"include":["jquery","bootstrap","validator","src/router/router.js"],//要压缩在一起的文件(会包括name对应的文件)
"out":"dest/libs.js"
}
}
}
});
grunt.loadNpmTasks('grunt-contrib-requirejs');
grunt.registerTask('default', ['requirejs']);
}

  需要说明的是name指定的文件内容会在main.js配置的依赖文件压缩之前压缩,但是如果include中还包含其他非main.js依赖的文件,则会在main.js非依赖文件后面压缩。

  我们的test.js源码为

 console.log("这是我随便测试用的一个js");

  然后我们执行:grunt

  结果在dest下生成一个libs.js压缩文件

  

  并且这个文件里面包含的压缩文件的顺序是:router.js->test.js->jquery.js-> bootstrap.min.js-> bootstrapValidator.min.js。

  所以说配置include中文件会依序压缩到libs.js,但是main.js依赖的文件会放在最后(依赖会逐层往上查找依赖),而name指定的文件会在非依赖文件之后依赖文件之前压缩。

  require模板文件打包

  模板文件使用到require工程上的text.js文件,路径:http://github.com/requirejs/text

  我们这里建立一个模板文件test.html

 <!DOCTYPE html>
<html>
<head>
<title>test</title>
</head>
<body>
</body>
</html>

  实际上现在test.html没有用到任何模板相关的运用,我们只是做打包例子,所以不管其他,我们只需要知道模板文件一般是html文件即可

  现在工程的文件结构是

  

  Gruntfile.js的源码为

 module.exports = function (grunt) {
grunt.initConfig({
"requirejs": {
"main": {
"options": {
baseUrl: ".",
paths: {
"jquery": "src/jquery",
"bootstrap": "src/bootstrap.min",
"validator": "src/bootstrapValidator.min",
"text": "text"//引入requirejs项目下解析模板引擎
},
shim: {
"bootstrap":["jquery"],
"beyond": ["bootstrap"],
"validator": ["bootstrap"]
},
"include":["jquery","bootstrap","validator","text!test.html"], "out":"dest/libs.js"
}
}
}
});
grunt.loadNpmTasks('grunt-contrib-requirejs');
grunt.registerTask('default', ['requirejs']);
}

  执行命令行:grunt

  dest文件下多了一个libs.js,查看其中是否有模板文件test.html中的内容

  

  说明模板被一同压缩进去了。关键是"text!test.html"这句话。test会将模板test.html解析成js脚本形式。

8.  cssmin打包样式文件


  需要用npm下载cssmin插件:npm install grunt-contrib-cssmin --save-dev

  Gruntfile.js文件源码

 module.exports = function (grunt) {
grunt.initConfig({
cssmin: {
compress: {
files: {
'dest/t.min.css': ["src/t1.css","src/t2.css"]
}
}
}
}); grunt.loadNpmTasks('grunt-contrib-cssmin'); }

  命令行执行:grunt cssmin

  两个css文件压缩打包到dest/t.min.css

9. htmlmin打包html文件


  需要用npm下载cssmin插件:npm install grunt-contrib-htmlmin --save-dev

  Gruntfile.js源码

 module.exports = function (grunt) {
grunt.initConfig({
htmlmin: {
main: {
options:{
removeComments: true,
collapseWhitespace: true
},
files:{
"dest/test.html": "test.html"
}
}
}
}); grunt.loadNpmTasks('grunt-contrib-htmlmin');
grunt.registerTask("default",["htmlmin"]);
}

  执行命令:grunt

  test.html压缩到dest/test.html

  

10. copy拷贝文件


  需要下载copy插件npm install grunt-contrib-copy --save-dev

  将src文件夹(包括内容和子文件内容)拷贝到dest目录下,Gruntfile.js源码

 module.exports = function (grunt) {
grunt.initConfig({
copy: {
main: {
expand: true,
src: 'src/**',
dest: 'dest/'
}
}
}); grunt.loadNpmTasks('grunt-contrib-copy');
grunt.registerTask("default",["copy"]);
}

  运行:grunt

  src被完美的拷贝到dest下

  

  只拷贝src的第一层子文件,Gruntfile.js源码

 module.exports = function (grunt) {
grunt.initConfig({
copy: {
main: {
expand: true,
src: 'src/*',
dest: 'dest/'
}
}
}); grunt.loadNpmTasks('grunt-contrib-copy');
grunt.registerTask("default",["copy"]);
}

  运行结果

  

  这个时候router是空文件夹。

  所以这里我们需要明白路径中“*”只表示当前这一层,“**”表示需要递归子文件夹   

  如果只是拷贝src中的内容而不用src包裹则需要cwd属性

 module.exports = function (grunt) {
grunt.initConfig({
copy: {
main: {
expand: true,
cwd: "src/",
src: '*',//也可以是数组形式["*"],可以过滤多种类型
dest: 'dest/'
}
}
}); grunt.loadNpmTasks('grunt-contrib-copy');
grunt.registerTask("default",["copy"]);
}

  执行结果是

  

  注意下面这种写法会报错

module.exports = function (grunt) {
grunt.initConfig({
copy: {
main: {
expand: true,
cwd: "src",
src: '/*',//会报错,不能以/开头,会被认为是绝对路径
dest: 'dest/'
}
}
}); grunt.loadNpmTasks('grunt-contrib-copy');
grunt.registerTask("default",["copy"]);
}

  拷贝src文件夹下指定类型的文件,Gruntfile.js源码

module.exports = function (grunt) {
grunt.initConfig({
copy: {
main: {
expand: true,
src: 'src/*.js',
dest: 'dest/'
}
}
}); grunt.loadNpmTasks('grunt-contrib-copy');
grunt.registerTask("default",["copy"]);
}

  执行:grunt

  结果src的js文件随src文件夹被拷贝

  

  递归拷贝src文件夹下所有子文件夹中的js文件

 module.exports = function (grunt) {
grunt.initConfig({
copy: {
main: {
expand: true,
src: 'src/**/*.js',
dest: 'dest/'
}
}
}); grunt.loadNpmTasks('grunt-contrib-copy');
grunt.registerTask("default",["copy"]);
}

  执行结果

  

  将所有指定类型的文件提取到同一层,Gruntfile.js源码

 module.exports = function (grunt) {
grunt.initConfig({
copy: {
main: {
flatten: true,//所有文件提取到dest下
expand: true,
src: 'src/**/**.js',
dest: 'dest/'
}
}
}); grunt.loadNpmTasks('grunt-contrib-copy');
grunt.registerTask("default",["copy"]);
}

  执行结果

  

  我们发现router/router.js被提取到了目标目录下,这也是flatten的作用

11. 使用contrib-watch和newer实时监听文件更改


  这里需要用到两个插件,下载这两个插件

  grunt-contrib-watch —— 作用是实现我们一开始需求的“自动化”!它会监听需要处理的文件的变动,一旦有变动就会自动执行相应处理。但是它有一个问题,就是每当监听到一处变动时,就会大费周章地把所有被监听的文件都处理一遍;

  grunt-newer —— 作用是处理上方watch的毛病,让watch在监听到某个文件变动时,仅仅对变动的文件进行事务处理。

  我们以合并压缩为例,Gruntfile.js源码

 module.exports = function (grunt) {
// 项目配置
grunt.initConfig({
uglify: {
my_target: {//该对象名称随意
files: {
'dest/libs.min.js': ['src/jquery.js', 'src/router.js']
}
}
},
watch: {
watchJs: {
files: ["src/**/*.js"],
tasks: ["newer:uglify"]//一旦监听到files中文件修改,立马触发uglify任务
}
}
});
// 加载提供"uglify"任务的插件
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-newer');
// 默认任务
grunt.registerTask('default', ['uglify',"watch"]);
}

  上面watch任务有一个子任务watchJs监听js的变动,一旦监听到files更改就触发uglify任务。

  

12. 使用autoprefixer自动为CSS规则添加最合适的前缀兼容浏览器


  Autoprefixer解析CSS文件并且添加浏览器前缀到CSS规则里,使用Can I Use的数据来决定哪些前缀是需要的。

  需要下载grunt-autoprefixer插件

  Gruntfile.js源码实例

 module.exports = function (grunt) {
// 项目配置
grunt.initConfig({
autoprefixer : {
my_target: {//该对象名称随意
expand:true,
src: "src/**/*.css",
dest: "dest/"
}
},
watch: {
watchJs: {
files: ["src/**/*.css"],
tasks: ["newer:autoprefixer"]//一旦监听到files中文件修改,立马触发任务
}
}
});
// 加载提供"uglify"任务的插件
grunt.loadNpmTasks('grunt-autoprefixer');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-newer');
// 默认任务
grunt.registerTask('default', ['newer:autoprefixer',"watch"]);
}

  这样监听了所有css更改,每次更改都会先添加浏览器兼容前缀。我们可以放心的在样式文件中按照最新的W3C规范来正常书写CSS而不需要浏览器前缀。

13. 总结


  总的来说grunt压缩打包都是基于插件,各种插件的作用可以查看官网文档。

  在运行任务函数指定的任务的时候可以通过冒号分割来传递参数。比如下面的例子

module.exports = function (grunt) {
//为了介绍自定义任务搞了一个这个
grunt.registerTask('test', '任务函数实例', function (arg1, arg2) {
if (arguments.length === 0) {
grunt.log.writeln(this.name + " 没有参数");
} else {
var join = Array.prototype.join;
grunt.log.writeln(this.name + " 的参数有" + join.call(arguments,","));
}
});
}

  执行:grunt test

  打印:

Runing “test” task
test 没有参数

  执行:grunt test:1

  打印:

Runing “test:1” (test) task
test 的参数有1

  执行:grunt test:1:2

  打印:

Runing “test:1:2” (test) task
test 的参数有1,2

  正常来说我们的html/css/js文件都是用不同的文件夹保存的,所以我们可以分成三种任务来处理。这些任务都可以配置在一起,最后一次性打包,这部分根据各自实际项目情况来处理。

  ok,如果你从头到尾看完并把上面的实例执行,那么grunt的基本功能就没有问题了。更多的需要看具体的插件使用了。

  

  码字不容易,求推荐。

  如果觉得本文不错,请点击右下方【推荐】!

前端打包构建工具grunt快速入门(大篇幅完整版)的更多相关文章

  1. 前端打包构建工具gulp快速入门

    因为之前一直有人给我推荐gulp,说他这里好哪里好的.实际上对我来说够用就行.grunt熟悉以后实际上他的配置也不难,说到效率的话确实是个问题,尤其项目大了以后,目前位置遇到的项目都还可以忍受.不过不 ...

  2. 前端项目构建工具---Grunt

    什么是Grunt? grunt是javascript项目构建工具,在grunt流行之前,前端项目的构建打包大多数使用ant.(ant具体使用 可以google),但ant对于前端而言,存在不友好,执行 ...

  3. 前端自动化构建工具Grunt

    一.了解Gurnt(http://www.open-open.com/lib/view/open1433898272036.html) Grunt 是一个基于任务的JavaScript工程命令行构建工 ...

  4. 前端自动化构建工具Gulp简单入门

    昨天听同事分享了Gulp的一些简单使用,决定自己也试一试. 一.安装 gulp是基于nodejs的,所以要先下载安装node(直接搜node,在官网下载就好了) 1.全局安装gulp npm inst ...

  5. 前端开发自动化工作流工具,JavaScript自动化构建工具grunt、gulp、webpack介绍

    前端开发自动化工作流工具,JavaScript自动化构建工具grunt.gulp.webpack介绍 前端自动化,这样的一个名词听起来非常的有吸引力,向往力.当今时代,前端工程师需要维护的代码变得及为 ...

  6. gulp前端自动化构建工具新手入门篇

    很久没有更新博文了. 经过了一次年前吐血的赶项目,终于在年后回血了.趁着有空,新学到了一个前端自动化构建工具-gulp. 现在我们通过这3个问题来学习一下: 1.什么是gulp? 2.为什么要用gul ...

  7. JavaScript自动化构建工具grunt、gulp、webpack介绍

    前端开发自动化工作流工具,JavaScript自动化构建工具grunt.gulp.webpack介绍 前端自动化,这样的一个名词听起来非常的有吸引力,向往力.当今时代,前端工程师需要维护的代码变得及为 ...

  8. 前端自动化构建工具 Gulp 使用

    一个月没写博客了,今天有时间,就写个gulp的入门使用吧.. 简介:gulp是一个前端自动化构建工具,可以实现代码的检查.压缩.合并……等等,gulp是基于Node.js的自动任务运行器 一.安装No ...

  9. 前端自动化构建工具webpack (一)之webpack安装 和 设置webpack.confi.js

    目的:  模块化开发,组件化开发,让代码符合开发规范,更高效 webpack作用:从pack,就知道这是包的意思,比较专业点叫做前端自动化打包构建工具,代码错误检查,预处理,文件合并(打包),代码压缩 ...

随机推荐

  1. 06.LoT.UI 前后台通用框架分解系列之——浮夸的图片上传

    LOT.UI分解系列汇总:http://www.cnblogs.com/dunitian/p/4822808.html#lotui LoT.UI开源地址如下:https://github.com/du ...

  2. clr 元数据

    clr相关编译器编译生成的托管模块由四部分组成:PE32或32+头.clr头.元数据.IL代码. 元数据和IL代码完全对应,保持一致(:>)性. 元数据有很多用途: VS的智能感知,自动补全: ...

  3. mybatis_映射查询

    一.一对一映射查询: 第一种方式(手动映射):借助resultType属性,定义专门的pojo类作为输出类型,其中该po类中封装了查询结果集中所有的字段.此方法较为简单,企业中使用普遍. <!- ...

  4. 趣说游戏AI开发:曼哈顿街角的A*算法

    0x00 前言 请叫我标题党!请叫我标题党!请叫我标题党!因为下面的文字既不发生在美国曼哈顿,也不是一个讲述美国梦的故事.相反,这可能只是一篇没有那么枯燥的关于算法的文章.A星算法,这个在游戏寻路开发 ...

  5. JavaWeb——Servlet

    一.基本概念 Servlet是运行在Web服务器上的小程序,通过http协议和客户端进行交互. 这里的客户端一般为浏览器,发送http请求(request)给服务器(如Tomcat).服务器接收到请求 ...

  6. ASP.NET MVC5----常见的数据注解和验证

    只要一直走,慢点又何妨. 在使用MVC模式进行开发时,数据注解是经常使用的(模型之上操作),下面是我看书整理的一些常见的用法. 什么是验证,数据注解 验证 从全局来看,发现逻辑仅是整个验证的很小的一部 ...

  7. canvas快速绘制圆形、三角形、矩形、多边形

    想看前面整理的canvas常用API的同学可以点下面: canvas学习之API整理笔记(一) canvas学习之API整理笔记(二) 本系列文章涉及的所有代码都将上传至:项目代码github地址,喜 ...

  8. SQL Server存储过程

    创建于2016-12-24 16:12:19 存储过程 概念: 1.存储过程是在数据库管理系统中保存的.预先编译的.能实现某种功能的SQL程序,它是数据库应用中运用比较广泛的 一种数据对象. 2.存储 ...

  9. 转:MSSQL还原单mdf文件报1813错误

    原文地址:http://www.cnblogs.com/clownkings/p/4950865.html 解决办法: 1.首先要备份好mdf文件,如果他没了经理非吃了你不可.都不吐骨头的. 2.在数 ...

  10. java的poi技术读取Excel数据到MySQL

    这篇blog是介绍java中的poi技术读取Excel数据,然后保存到MySQL数据中. 你也可以在 : java的poi技术读取和导入Excel了解到写入Excel的方法信息 使用JXL技术可以在 ...