引入:grunt是一套前端自动化工具,一个基于nodeJs的命令行工具,一般用于:
- ① 压缩文件
- ② 合并文件
- ③ 简单语法检查
环境:grunt是基于nodejs运行的,所以需要有nodejs,在Nodejs中,安装grunt的命令行接口。
npm install -g grunt-cli
将grunt命令植入系统路径。通过nodejs的require查找到安装的grunt,就能在任意目录下运行grunt项目了。
在一个简单的实例中,慢慢享受grunt给前端所带来的便捷与随心所欲。
新建项目的时候,增加两个文件,一个为:package.json;另一个为:Gruntfile.js。
package.json
这个文件用来存储npm模块的依赖项(比如我们的打包若是依赖requireJS的插件,这里就需要配置)
然后,我们会在里面配置一些不一样的信息,比如我们上面的file,这些数据都会放到package中
对于package的灵活配置。
Gruntfile
这个文件尤其关键,他一般干两件事情:
① 读取package信息
② 插件加载、注册任务,运行任务(grunt对外的接口全部写在这里面)
Gruntfile一般由四个部分组成
① 包装函数
这个包装函数没什么东西,意思就是我们所有的代码必须放到这个函数里面
module.exports = function (grunt) {
//你的代码
}
这个不用知道为什么,直接将代码放入即可
② 项目/任务配置
我们在Gruntfile一般第一个用到的就是initConfig方法配置依赖信息
pkg: grunt.file.readJSON('package.json')
这里的 grunt.file.readJSON就会将我们的配置文件读出,并且转换为json对象
然后我们在后面的地方就可以采用pkg.XXX的方式访问其中的数据了
值得注意的是这里使用的是underscore模板引擎,所以你在这里可以写很多东西
uglify是一个插件的,我们在package依赖项进行了配置,这个时候我们为系统配置了一个任务
uglify(压缩),他会干这几个事情:
① 在src中找到zepto进行压缩(具体名字在package中找到)
② 找到dest目录,没有就新建,然后将压缩文件搞进去
③ 在上面加几个描述语言
这个任务配置其实就是一个方法接口调用,按照规范来就好,暂时不予关注,内幕后期来
这里只是定义了相关参数,但是并未加载实际函数,所以后面马上就有一句:
grunt.loadNpmTasks('grunt-contrib-uglify');
用于加载相关插件
最后注册一个自定义任务(其实也是默认任务),所以我们下面的命令行是等效的:
grunt == grunt uglify
实例:
1 js压缩打包
package.json文件
{
"name": "demo",
"file": "zepto",
"version": "0.1.0",
"description": "demo",
"license": "MIT",
"devDependencies": {
"grunt": "~0.4.1",
"grunt-contrib-jshint": "~0.6.3",
"grunt-contrib-uglify": "~0.2.1",
"grunt-contrib-requirejs": "~0.4.1",
"grunt-contrib-copy": "~0.4.1",
"grunt-contrib-clean": "~0.5.0",
"grunt-strip": "~0.2.1"
},
"dependencies": {
"express": "3.x"
}
}
1->1(一个文件打包压缩到另一个文件):
module.exports = function (grunt) {
banner: '/*! <%= pkg.file %>Qboooogle <%= grunt.template.today("yyyy-mm-dd") %> */\n'
},
build: { src: 'build/js/<%=pkg.file %>.js',
dest: 'dist/js/<%= pkg.file %>.min.js'
}
}
N->1(N个文件打包压缩到一个文件):
module.exports = function (grunt) {
banner: '/*! <%= pkg.file %>Qboooogle <%= grunt.template.today("yyyy-mm-dd") %> */\n'
},
build: {
src: ['build/js/<%=pkg.file %>.js','build/js/<%=pkg.file %>1.js'], dest: 'dist/js/<%= pkg.file %>.min.js'
}
}
N->N(通过my_target):
module.exports = function (grunt) {
options: {
banner: '/*! <%= pkg.file %> Qboooogle <%= grunt.template.today("yyyy-mm-dd") %> */\n'
},
my_target : {
files : {
'dist/js/index.min.js':['build/js/index.js'],
'dist/js/index1.min.js':['build/js/index1.js'],
'dist/js/index2.min.js':['build/js/index1.js'],
'dist/js/index3.min.js':['build/js/index1.js']
}
}
}
2 less编译打包
N->N
less : {
development: {
options: {
compress: true
},
files: {
"dist/css/index1.css":"build/less/index1.less",
"dist/css/index.css" : "build/less/index.less"
}
}
}
N->1(将build/less/下的两个文件编译合并到dist/css/目录下)
module.exports = function (grunt) {
less : {
development: {
options: {
compress: false
},
files: {
"dist/css/index.css":["build/less/index1.less","build/less/index.less"]
}
}
}
开发模式与产品模式(唯一区别就是开发模式下,为了进行调试,尽量不压缩文件,而上线版本,最好将其进行压缩)代码表示将build/less/下的两个Less文件转化为dist/css/下的css文件,两者前者为未压缩版本。
module.exports = function (grunt) {
less : {
development: {
options: {
compress: false
},
files: {
"dist/css/index.css":["build/less/index1.less","build/less/index.less"]
}
},
production: {
options: {
compress: true
},
files: {
"dist/css/index4.css":["build/less/index1.less","build/less/index.less"]
}
}
}
3 图片优化(将图片进行优化处理,并生成新的文件,存放在另一个文件夹中)这里表示,匹配build/img下面的所有以png,jpg,gif,svg,jpeg格式结尾的文件,并一一进行优化处理,然后将优化后的图片放在dist/img/目录下。
image : {
dynamic : {
files:[{
expand:true,
cwd:'build/img/',
src:['**/*.{png,jpg,gif,svg,jpeg'],
dest:'dist/img/'
}]
}
}
});
4 js语法检查(按照自定义的标准,检测绑定的相关js文件是否有语法错误)
jshint : {
options: {
jshintrc :'.jshintrc'
},
core: {
src:'dist/js/index.min.js'
},
demo: {
src:'dist/js/index1.min.js'
}
}
5 监听(watch):通过绑定所有的js文件及less文件,并时时监听文件内容的变化,当变化发生时,将重新编译、压缩、打包生成最新的文件。
uglify: {
options: {
banner: '/*! <%= pkg.file %> Qboooogle <%= grunt.template.today("yyyy-mm-dd") %> */\n'
},
build : {
src: 'build/js/index.js',
dest:'dist/js/index6.min.js'
}
},
watch: {
files: ["build/less/*.less","build/js/*.js"],
tasks: ["less", "uglify"]
},
6 清理文件(构建成功后,将不再需要的文件删除,比如图片优化之后,之前的图片就可以清理掉了)
clean: {
build: ["build/img/*"]
},
7 css文件校验处理
csslint: {
options: {
csslintrc: 'build/less/.csslintrc'
},
dist:[
'dist/css/index1.css',
]
}
8 链接Bootstrap HTML 并进行语法检查
bootlint: {
options: {
relaxerror: ['W002','W003','W005','W007']
},
files: ['*.html']
},
9 构建HTML模板
includes: {
build: {
src: ['*.html'], // Source files
dest: 'documentation/', // Destination directory
flatten: true,
cwd: 'documentation/build',
options: {
silent: true,
includePath: 'documentation/build/include'
}
}
其中css链接处理需要的.jshintrc文件如下:
{
"adjoining-classes": false,
"box-sizing": false,
"box-model": false,
"compatible-vendor-prefixes": false,
"floats": false,
"font-sizes": false,
"gradients": false,
"important": false,
"known-properties": false,
"outline-none": false,
"qualified-headings": false,
"regex-selectors": false,
"shorthand": false,
"text-indent": false,
"unique-headings": false,
"universal-selector": false,
"unqualified-attributes": false,
"ids": false,
"fallback-colors": false,
"vendor-prefix": false,
"import": false
}
完整的Gruntfile.js文件如下:
module.exports = function (grunt) {
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
uglify: {
options: {
banner: '/*! <%= pkg.file %> Qboooogle <%= grunt.template.today("yyyy-mm-dd") %> */\n'
},
build : {
src: 'build/js/index.js',
dest:'dist/js/index6.min.js'
}
},
watch: {
files: ["build/less/*.less","build/js/*.js"],
tasks: ["less", "uglify","image","clean"]
},
concat: {
options: {
separator: ';'
},
dist: {
src:["build/less/index1.less","build/less/index.less"],
dest:"build/less/index3.less"
}
},
less : {
development: {
options: {
compress: false
},
files: {
"dist/css/index6.css":["build/less/index1.less","build/less/index.less"]
}
},
production: {
options: {
compress: true
},
files: {
"dist/css/index5.css":["build/less/index1.less","build/less/index.less"]
}
}
},
clean: {
build: ["build/img/*"]
},
uglify: {
options: {
mangle:true,
preserveComments:'some'
}
}, cssmin: {
compress: {
files: {
"dist/css/index.css": [
"build/less/index1.less",
"build/less/index.less"
]
}
}
}
image: {
dynamic: {
files: [{
expand: true,
cwd: 'build/img/',
src: ['**/*.{png,jpg,gif,svg,jpeg}'],
dest: 'dist/img/'
}]
}
},
csslint: {
options: {
csslintrc: 'build/less/.csslintrc'
},
dist:[
'dist/css/index1.css',
]
},
bootlint: {
options: {
relaxerror: ['W002','W003','W005','W007']
},
files: ['*.html']
},
includes: {
build: {
src: ['*.html'], // Source files
dest: 'documentation/', // Destination directory
flatten: true,
cwd: 'documentation/build',
options: {
silent: true,
includePath: 'documentation/build/include'
}
}
}
jshint : {
options: {
jshintrc :'.jshintrc'
},
core: {
src:'dist/js/index.min.js'
},
demo: {
src:'dist/js/index1.min.js'
}
}
}); grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-image');
grunt.loadNpmTasks('grunt-contrib-less');
grunt.loadNpmTasks('grunt-contrib-clean');
grunt.loadNpmTasks('grunt-contrib-csslint');
grunt.loadNpmTasks('grunt-bootlint');
grunt.loadNpmTasks('grunt-includes');
grunt.loadNpmTasks("grunt-contrib-concat");
grunt.loadNpmTasks("grunt-contrib-watch");
grunt.loadNpmTasks("grunt-contrib-uglify");
grunt.loadNpmTasks('grunt-contrib-cssmin'); grunt.registerTask('link', ['includes']);
grunt.registerTask('default', ['includes']);
// Linting task
//grunt.registerTask('lint', ['jshint', 'csslint', 'bootlint']); // The default task (running "grunt" in console) is "watch"
//grunt.registerTask('default', ['watch']);
}
完整的目录结构如下:
aaarticlea/png;base64,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" alt="" />
整项目代码下载:Qboooogle