grunt的安装与使用
Grunt是基于Node.js的javascript项目构建工具。它的工作就是运行你所设定的批处理任务。其实去年这个时候我已经开始用上grunt,这篇文章是给师弟师妹们学习之用。现阶段利用github几乎必须学会使用grunt,因为大多数javascript项目都用该工具进行项目管理,不用grunt连登堂入室都做不到。
一.安装及使用流程
1)首先确定无论你是什么系统(windows、linux、macOS),系统里面都已经装好了nodejs。可通过在命令行输入npm -v或者node -v查看版本,来确定nodejs是否安装,没有就去nodejs.org上面去下载安装。
2)在全局中安装grunt客户端:在命令行输入 client npm install -g grunt-cli按回车。
说明:grunt有二个部分:服务器端(grunt)和客户端(grunt-cli)。grunt-cil的任务很简单:允许在命令行中输入grunt, 调用与Gruntfile.js在同一目录中的grunt服务器端程序。所以安装grunt-cli并不等于安装了grunt!每个要使用grunt的工程目录下还要安装grunt服务端版本,具体请看步骤4的说明。
3)找一个大牛们的工程耍耍,例如github上的angularjs,或者bootstrap,git clone到自己的测试文件夹下。
4)在目标工程项目中安装grunt服务器端:打开命令行,切到该工程的根目录,输入npm install按回车。
说明:grunt是基于nodejs的项目构建工具,因此使用npm包管理工具安装即可。一般而言,grunt 和 grunt 插件都会在这些项目根目录下的package.json文件中定义。这样就可以通过一个命令将当前项目依赖的模块安装完毕。(如果grunt没有在项目的package.json文件中定义,则无法执行之后的grunt命令,需要使用npm install grunt命令安装grunt服务器端)
事实上,对于每个项目,都要执行相似的工作,从而对每个项目生成其特定的grunt版本。这是很正常的,因为不同项目可能需要不同的grunt模块,或者同一个模块的不同版本,故而一个项目一个grunt服务是最好的结果。
5)执行grunt批处理功能:在命令行输入grunt按回车。之后会按gruntfile.js中预定义的批处理命令生成各种文件。看看命令行的提示,以及目录中多了什么文件。OK,到这里你已经学会怎么用grunt了。
二. package.json文件的书写
虽然我们已经会使用grunt执行命令,但是还不会写这些命令。学会使用grunt进行批处理的关键是学会写package.json和gruntfile.js这两个文件。package.json是定义依赖包的目录文件,而gruntfile.js是批处理命令文件。package.json比较简单,上github多看几个大牛工程的package.json就知道怎么写了。考虑到初学者看到太大段的文字可能看不懂,我这里提供一个简短的例子,来自于robin项目:
{ "name": "robin_zycj", "version": "1.0.0", "devDependencies": { "grunt": "~0.4.1", "grunt-contrib-clean": "0.4.0", "grunt-contrib-compress": "0.4.1", "grunt-contrib-concat": "~0.2.0", "grunt-contrib-connect": "0.1.2", "grunt-contrib-copy": "~0.5.0", "grunt-contrib-csslint": "~0.1.1", "grunt-contrib-cssmin": "~0.5.0", "grunt-contrib-imagemin": "~0.1.2", "grunt-contrib-less": "~0.11.1", "grunt-contrib-uglify": "~0.2.0", "grunt-css": ">0.0.0", "grunt-string-replace": "^0.2.7" } }
grunt及grunt的插件都定义在devDenpendencies属性中。其中grunt-contrib系列插件都是由grunt主团队维护的。每个插件之后定义的是其版本号:如果只是“0.1.2”这样的数字,表示只安装这个版本。如果加了波浪号~,表示允许该插件自动升级。根据需求选择版本。
三. gruntfile.js文件的书写
这个gruntfile.js中定义的是grunt的批处理命令。根据需求不同、所用插件不同,差别很大,所以不能一概而论。这里我只给出一个我以前自动处理robin项目前端文件的gruntfile.js,并添加了些注释作为参考。
module.exports = function (grunt) { // 给grunt新建些设置 grunt.initConfig({ //首先把目录拷贝到指定位置 copy: { main: { files: [ // 拷贝整个目录 {expand: true, cwd: '../views/zoro/', src: ['**'], dest: 'zoro/'}, // 拷贝全部图片文件夹到指定目录 {expand: true, flatten: false, cwd: '../views/zoro/module/download/css/images/', src: ['**'], dest: 'zoro/module/cssmin/images/'}, {expand: true, flatten: false, cwd: '../views/zoro/module/files/css/images/', src: ['**'], dest: 'zoro/module/cssmin/images/'}, {expand: true, flatten: false, cwd: '../views/zoro/module/platform/css/images/', src: ['**'], dest: 'zoro/module/cssmin/images/'}, {expand: true, flatten: false, cwd: '../views/zoro/module/robin/cssv2/images/', src: ['**'], dest: 'zoro/module/cssmin/images/'}, ] }, }, //对一些文件进行字符串替换工作,这样做是为了避免修改主版本代码的情况下生成新代码 'string-replace': { robin: { files: { 'zoro/module/robin/robin.js': '../views/zoro/module/robin/robin.js', }, options: { replacements: [ { pattern: "require('less');", replacement: '' }, { pattern: 'require("module/robin/cssv2/robin.less");', replacement: 'require("module/cssmin/all.min.css");' } ] } }, init: { files: { 'zoro/init.js': '../views/zoro/init.js', }, options: { replacements: [ { pattern: "'less' : 'core/less',", replacement: '' }, { pattern: ",preload : ['core/plugin-less']", replacement: '' } ] } }, download: { files: { 'zoro/download.php': '../views/zoro/download.php', }, options: { replacements: [ { pattern: '<link rel="stylesheet/less" type="text/css" href="/application/views/zoro/module/main/css/base.less">', replacement: '<link rel="stylesheet" type="text/css" href="/application/views/zoro/module/cssmin/all.min.css">' }, { pattern: '<link rel="stylesheet/less" type="text/css" href="/application/views/zoro/module/robin/cssv2/reset.less">', replacement: '' }, { pattern: '<link rel="stylesheet/less" type="text/css" href="/application/views/zoro/module/robin/cssv2/robin.less">', replacement: '' }, { pattern: '<link rel="stylesheet/less" type="text/css" href="/application/views/zoro/module/download/css/styles.less">', replacement: '' }, { pattern: '<script src="/application/views/zoro/core/less.js" type="text/javascript"></script>', replacement: '' } ] } }, others: { files: { 'zoro/module/circles/circles.js': '../views/zoro/module/circles/circles.js', 'zoro/module/files/files.js': '../views/zoro/module/files/files.js', 'zoro/module/files/files_sync.js': '../views/zoro/module/files/files_sync.js', 'zoro/module/files/receives.js': '../views/zoro/module/files/receives.js', 'zoro/module/files/recycles.js': '../views/zoro/module/files/recycles.js', 'zoro/module/platform/platform.js': '../views/zoro/module/platform/platform.js', }, options: { replacements: [ { pattern: 'require("module/circles/css/circle.less");', replacement: '' }, { pattern: 'require("module/files/css/file.less");', replacement: '' }, { pattern: 'require("module/files/css/recycle.less");', replacement: '' }, { pattern: 'require("module/files/css/share.less");', replacement: '' }, { pattern: 'require("module/files/css/receive.less");', replacement: '' }, { pattern: 'require("module/files/css/linkman.less");', replacement: '' }, { pattern: 'require("module/platform/css/platform.less");', replacement: '' } ] } } }, //解码less less: { development: { options: { compress: true, }, files: { "zoro/module/main/css/base.css": "../views/zoro/module/main/css/base.less", "zoro/module/robin/css/reset.css": "../views/zoro/module/robin/css/reset.less", "zoro/module/robin/css/robin.css": "../views/zoro/module/robin/css/robin.less", "zoro/module/robin/cssv2/reset.css": "../views/zoro/module/robin/cssv2/reset.less", "zoro/module/robin/cssv2/robin.css": "../views/zoro/module/robin/cssv2/robin.less", "zoro/module/files/css/file.css": "../views/zoro/module/files/css/file.less", "zoro/module/files/css/linkman.css": "../views/zoro/module/files/css/linkman.less", "zoro/module/files/css/receive.css": "../views/zoro/module/files/css/receive.less", "zoro/module/files/css/recycle.css": "../views/zoro/module/files/css/recycle.less", "zoro/module/files/css/share.css": "../views/zoro/module/files/css/share.less", "zoro/module/platform/css/platform.css": "../views/zoro/module/platform/css/platform.less", "zoro/module/download/css/styles.css": "../views/zoro/module/download/css/styles.less", } } }, //把解码好的css文件组合压缩成一个文件,cssmin是CSS压缩工具 cssmin: { add_banner: { options: { banner: '/* 10 in one, view gruntfile.js */' }, files: { 'zoro/module/cssmin/all.min.css': [ // "zoro/module/main/css/base.css", // "zoro/module/robin/cssv2/reset.css", "zoro/module/robin/cssv2/robin.css", "zoro/module/files/css/file.css", "zoro/module/files/css/linkman.css", "zoro/module/files/css/receive.css", "zoro/module/files/css/recycle.css", "zoro/module/files/css/share.css", "zoro/module/platform/css/platform.css", "zoro/module/download/css/styles.css" ] } } }, //uglify是js压缩工具 uglify: { options: { mangle: false, //不混淆变量名 preserveComments: 'all', //不删除注释,还可以为 false(删除全部注释),some(保留@preserve @license @cc_on等注释) banner: '/*! <%= grunt.template.today("yyyy-mm-dd") %> */\n'//添加banner }, buildall: {//按原文件结构压缩js文件夹内所有JS文件 files: [ { expand: true, src: 'zoro/module/**/*.js',//所有js文件 dest: ''//生成的文件就输出到原目录下 } ] }, } }); // 载入插件 grunt.loadNpmTasks('grunt-contrib-copy'); grunt.loadNpmTasks('grunt-string-replace'); grunt.loadNpmTasks('grunt-contrib-less'); grunt.loadNpmTasks('grunt-contrib-cssmin'); grunt.loadNpmTasks('grunt-contrib-uglify'); // 默认任务 grunt.registerTask('default', ['copy', 'string-replace', 'less', 'cssmin', 'uglify']); };