上一篇博客,咱们简单的介绍了grunt的使用,一些基础点没能覆盖,咱们今天有必要看看一些基础知识css
【grunt第一弹】30分钟学会使用grunt打包前端代码html
前面咱们简单的介绍了grunt相关的知识,这里咱们这里还须要再熟悉下Gruntfile相关的知识点,好比说配置任务前端
grunt的任务配置都是在Gruntfile中的grunt.initConfig方法中指定的,这个配置主要都是一些命名性属性
好比咱们上次用到的合并以及压缩的任务配置:node
grunt.initConfig({ concat: { //这里是concat任务的配置信息 }, uglify: { //这里是uglify任务的配置信息 }, //任意非任务特定属性 my_property: 'whatever', my_src_file: ['foo/*.js', 'bar/*.js'] });
其中的my_property彻底可能读取外部json配置文件,而后在上面任务配置中即可以,好比咱们要压缩的文件为准或者最后要放到哪里,即可以在此配置jquery
咱们使用grunt的时候,主要工做就是配置任务或者建立任务,实际上就是作一个事件注册,而后由咱们触发之,因此grunt的核心仍是事件注册
每次运行grunt时,咱们能够指定运行一个或者多个任务,经过任务决定要作什么,好比咱们同时要压缩和合并还要作代码检查web
grunt.registerTask('default', ['jshint','qunit','concat','uglify']);
当运行一个基本任务时,grunt并不会查找配置和检查运行环境,他仅仅运行指定的任务函数,能够传递冒号分割参数,好比:express
grunt.registerTask('foo', 'A sample task that logs stuff.', function (arg1, arg2) { if (arguments.length === 0) { grunt.log.writeln(this.name + ", no args"); } else { grunt.log.writeln(this.name + ", " + arg1 + " " + arg2); } });
运行结果以下:编程
$ grunt foo:testing:123 Running "foo:testing:123" (foo) task foo, testing 123 $ grunt foo:testing Running "foo:testing" (foo) task foo, testing undefined $ grunt foo Running "foo" task foo, no args
这里有个多任务的状况,就是一个任务里面实际上第一了多个东东,这个时候就有所不一样json
grunt.initConfig({ log: { demo01: [1,2,3], demo02: 'hello world', demo03: false } }); grunt.registerTask('log','log stuff.', function(){ grunt.log.writeln(this.target + ': ' + this.data); });
若是咱们运行,运行状况以下:app
???????
更多时候,咱们实际场景中都会须要自定义任务,而在咱们任务内部使用 grunt.task.run({}) 运行任务
这块的知识点,咱们后面以实际例子说明
学习grunt主要就是学习grunt的插件使用,因此咱们今天先来学习经常使用的几个插件
咱们仍然以简单例子学习
module.exports = function (grunt) { grunt.initConfig({ uglify: { my_target: { files: { 'dest/libs.min.js': ['src/zepto.js', 'src/underscoce.js'] } } } }); grunt.loadNpmTasks('grunt-contrib-uglify'); }
这样会将src里面的zepto等文件打包值dest的lib.min.js中
而后这段代码很是有意思,他会将一个文件目录里面的全部js文件打包到另外一个文件夹
module.exports = function (grunt) { grunt.initConfig({ uglify: { my_target: { files: [{ expand: true, cwd: 'src', src: '**/*.js', dest: 'dest' }] } } }); grunt.loadNpmTasks('grunt-contrib-uglify'); }
如果你但愿给你文件的头部加一段注释性语言配置banner信息便可
grunt.initConfig({ pkg: grunt.file.readJSON('package.json'), uglify: { options: { banner: '/*! 注释信息 */' }, my_target: { files: { 'dest/output.min.js': ['src/input.js'] } } } });
该插件主要用于代码合并,将多个文件合并为一个,咱们前面的uglify也提供了必定合并的功能
在可选属性中咱们能够设置如下属性:
① separator 用于分割各个文件的文字,
② banner 前面说到的文件头注释信息,只会出现一次
③ footer 文件尾信息,只会出现一次
④ stripBanners去掉源代码注释信息(只会清楚/**/这种注释)
一个简单的例子:
module.exports = function (grunt) { grunt.initConfig({ concat: { options: { separator: '/*分割*/', banner: '/*测试*/', footer: '/*footer*/' }, dist: { src: ['src/zepto.js', 'src/underscore.js', 'src/backbone.js'], dest: 'dist/built.js', } } }); grunt.loadNpmTasks('grunt-contrib-concat'); }
合并三个文件为一个,这种在咱们源码调试时候颇有意义
有时候咱们可能须要将合并的代码放到不一样的文件,这个时候能够这样干
module.exports = function (grunt) { grunt.initConfig({ concat: { basic: { src: ['src/zepto.js'], dest: 'dest/basic.js' }, extras: { src: ['src/underscore.js', 'src/backbone.js'], dest: 'dest/with_extras.js' } } }); grunt.loadNpmTasks('grunt-contrib-concat'); }
这种功能还有这样的写法:
module.exports = function (grunt) { grunt.initConfig({ concat: { basic_and_extras: { files: { 'dist/basic.js': ['src/test.js', 'src/zepto.js'], 'dist/with_extras.js': ['src/underscore.js', 'src/backbone.js'] } } } }); grunt.loadNpmTasks('grunt-contrib-concat'); }
第二种写法便于使用配置文件,具体各位选取吧,至于读取配置文件的东西咱们这里就先不关注了
该插件用于检测文件中的js语法问题,好比我test.js是这样写的:
alert('我是叶小钗')
module.exports = function (grunt) { grunt.initConfig({ jshint: { all: ['src/test.js'] } }); grunt.loadNpmTasks('grunt-contrib-jshint'); }
运行结果是:
$ grunt jshint Running "jshint:all" (jshint) task Linting src/test.js ...ERROR [L1:C15] W033: Missing semicolon. alert('我是叶小钗')
说我缺乏一个分号,好像确实缺乏.....若是在里面写明显的BUG的话会报错
多数时候,咱们认为没有分号无伤大雅,因此,咱们文件会忽略这个错误:
jshint: { options: { '-W033': true }, all: ['src/test.js'] }
这里有一个稍微复杂的应用,就是咱们合并以前作一次检查,合并以后再作一次检查,咱们能够这样写
module.exports = function (grunt) { grunt.initConfig({ concat: { dist: { src: ['src/test01.js', 'src/test02.js'], dest: 'dist/output.js' } }, jshint: { options: { '-W033': true }, pre: ['src/test01.js', 'src/test02.js'], after: ['dist/output.js'] } }); grunt.loadNpmTasks('grunt-contrib-concat'); grunt.loadNpmTasks('grunt-contrib-jshint'); }
$ grunt jshint:pre concat jshint:after Running "jshint:pre" (jshint) task >> 2 files lint free. Running "concat:dist" (concat) task File "dist/output.js" created. Running "jshint:after" (jshint) task >> 1 file lint free.
这里连续运行了三个任务,先作检查再合并,而后作检测,我这里写了两个简单的文件,若是将jquery搞进去的话,好像还出了很多BUG......
因此真的要用它还要自定一些规范,咱们这里暂时到这里,先进入下一个插件学习
咱们的grunt打包程序极有可能与requirejs一块儿使用,可是几个插件学习下来又属requireJs的使用最为麻烦,由于网上资源不多,搞到这一段耗掉了我不少精力
这个时候你就会感叹,英语好不必定编程好,英语差想成为高手仍是不简单啊!!!
requirejs: { compile: { options: { baseUrl: "path/to/base", mainConfigFile: "path/to/config.js", name: "path/to/almond", // assumes a production build using almond out: "path/to/optimized.js" } } }
官方的例子首先就是这几个属性:
baseUrl 表明全部的js文件都会相对于这个目录
mainConfigFile 配置文件目录
name ???
out 输出文件
一些参数咱们不太了解,这个时候就只能以例子破之了
module.exports = function (grunt) { grunt.initConfig({ requirejs: { compile: { "options": { "baseUrl": "./", "paths": { "$": "src/zepto", "_": "src/underscore", "B": "src/backbone", "Test": "src/Test01" }, "include": [ "$", "_", "B", "Test" ], "out": "dest/libs.js" } } } }); grunt.loadNpmTasks('grunt-contrib-requirejs'); }
这样配置后,会将include里面的文件打包为out对应的文件,paths的自己意义不大,就是用于配置include里面的指向
这个时候咱们来加个name看看有神马做用:
module.exports = function (grunt) { grunt.initConfig({ requirejs: { compile: { "options": { "baseUrl": "./", "name": 'src/test02.js', "paths": { "$": "src/zepto", "_": "src/underscore", "B": "src/backbone", "Test": "src/Test01" }, "include": [ "$", "_", "B", "Test" ], "out": "dest/libs.js" } } } }); grunt.loadNpmTasks('grunt-contrib-requirejs'); }
这样的话,会将name对应文件压缩到压缩文件的最前面,可是具体是干什么的,仍是不太清楚,其英文注释说是单个文件或者其依赖项优化,不知道优化什么啊。。。囧!!!
requireJS基本的用法就是这样了,其详细信息,咱们过段时间再来看看,下面说一下requireJS的其它用法
咱们这里将requireJS的配置信息放在外面,而Gruntfile采用自定义任务的方式完成上面的功能
配置文件/cfg.json
{requirejs: { "options": { "baseUrl": "./", "paths": { "$": "src/zepto", "_": "src/underscore", "B": "src/backbone", "Test": "src/Test01" }, "include": [ "$", "_", "B", "Test" ], "out": "dest/libs.js" } }}
而后,这里咱们便不是有initConfig的作法了,直接使用自定义任务
module.exports = function (grunt) { grunt.loadNpmTasks('grunt-contrib-requirejs'); grunt.registerTask('build', 'require demo', function () { //第一步,读取配置信息 var cfg = grunt.file.readJSON('cfg.json'); cfg = cfg.requirejs; grunt.config.set('requirejs', { test: cfg }); //第二步,设置参数 grunt.log.debug('参数:' + JSON.stringify(grunt.config())); //第三步跑任务 grunt.task.run(['requirejs']); }); }
$ grunt build --debug Running "build" task [D] Task source: d:\grunt\Gruntfile.js [D] 参数:{"requirejs":{"test":{"options":{"baseUrl":"./","paths":{"$":"src/zept o","_":"src/underscore","B":"src/backbone","Test":"src/Test01"},"include":["$"," _","B","Test"],"out":"dest/libs.js"}}}} Running "requirejs:test" (requirejs) task [D] Task source: d:\grunt\node_modules\grunt-contrib-requirejs\tasks\requirejs.j s >> Tracing dependencies for: d:/grunt/dest/libs.js >> Uglifying file: d:/grunt/dest/libs.js >> d:/grunt/dest/libs.js >> ---------------- >> d:/grunt/src/zepto.js >> d:/grunt/src/underscore.js >> d:/grunt/src/backbone.js >> d:/grunt/src/Test01.js
效果仍是有的,最后咱们介绍下requireJS打包模板文件
咱们知道,模板文件通常都是html,好比咱们这里的demo01.html,对于这个文件咱们应该怎么打包呢?其实很简单......
须要干两件事情:
① 引入require.text
② 加入模板文件
{ "requirejs": { "options": { "baseUrl": "./", "paths": { "$": "src/zepto", "_": "src/underscore", "B": "src/backbone", "test": "src/test01", "text": "src/require.text" }, "include": [ "$", "_", "B", "test", "text!src/demo01.html" ], "out": "dest/libs.js" } } }
因而,咱们便成功将模板打入了
$ grunt build --debug Running "build" task [D] Task source: d:\grunt\Gruntfile.js [D] 参数:{"requirejs":{"test":{"options":{"baseUrl":"./","paths":{"$":"src/zept o","_":"src/underscore","B":"src/backbone","test":"src/test01","text":"src/requi re.text"},"include":["$","_","B","test","text!src/demo01.html"],"out":"dest/libs .js"}}}} Running "requirejs:test" (requirejs) task [D] Task source: d:\grunt\node_modules\grunt-contrib-requirejs\tasks\requirejs.j s >> Tracing dependencies for: d:/grunt/dest/libs.js >> Uglifying file: d:/grunt/dest/libs.js >> d:/grunt/dest/libs.js >> ---------------- >> d:/grunt/src/zepto.js >> d:/grunt/src/underscore.js >> d:/grunt/src/backbone.js >> d:/grunt/src/test01.js >> d:/grunt/src/require.text.js >> text!src/demo01.html
在文件中咱们引用方式是:
"text!src/demo01.html" => '具体文件'
样式文件的打包方式与js不太同样,这里咱们下载css-min插件,而且在package.json中新增依赖项
{ "name": "demo", "version": "0.1.0", "description": "demo", "license": "MIT", "devDependencies": { "grunt": "~0.4.1", "grunt-contrib-jshint": "~0.6.3", "grunt-contrib-concat": "~0.3.0", "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", "grunt-contrib-watch": "~0.6.0", "grunt-contrib-cssmin": "~0.5.0" }, "dependencies": { "express": "3.x" } }
module.exports = function (grunt) { grunt.initConfig({ cssmin: { compress: { files: { 'dest/car.min.css': [ "src/car.css", "src/car01.css" ] } } } }); grunt.loadNpmTasks('grunt-contrib-cssmin'); }
如此一来咱们即可以压缩合并CSS文件了:
$ grunt cssmin --debug Running "cssmin:compress" (cssmin) task [D] Task source: d:\grunt\node_modules\grunt-contrib-cssmin\tasks\cssmin.js File dest/car.min.css created.
今天,咱们一块儿来学习了一些grunt打包的基础知识,明天咱们就进行下面的学习,简单结束这一轮grunt相关的知识
咱们的开发版本与使用版本可能不在一个位置哦
不一样分支打包
在HTML5嵌入webview的时代,咱们固然存在一次打包既要造成网站文件也要造成app文件
固然可能存在分频道分分支打包的状况
今日到此为止,待续......