Grunt和Gulp是Javascript世界里的用来做自动压缩、Typescript编译、代码质量lint工具、css预处理器的构建工具,它帮助开发者处理客户端开发中的一些烦操重复性的工作。Grunt和Gulp都在Visual studio 2015中得到支持。ASP.NET 项目模板默认使用Gulp。
Grunt和Gulp有什么区别?Gulp虽然是稍微晚一点登场的,但是它因crisp performance和优雅的语法受到欢迎。与Grunt不同,Grunt往往在硬盘上是读写文件,Gulp使用流式的API去链式的调用方法,Grunt是早些出现的客户端构建工具,Grunt预定义了大多数经常要做的压缩和单元测试等工作。Grunt每天都有数以千计的下载和应用。
这个实例使用Empty ASP.NET项目模板来展示自动化的客户端构建工作。非空的ASP.NET项目模板默认使用Gulp。
最终示例清理目标部署目录,合并Javascript文件,检查代码质量,压缩Javascript文件内容并且部署到web项目的跟目录,我们将使用以下包:
grunt:任务执行者包;
grunt-contrib-clean:一个用来移除文件和目录的任务
grunt-contrib-jshint:一个审查代码质量的任务
grunt-contrib-concat:一个连接多文件在一个文件中的任务
grunt-contrib-uglify:一个压缩和缩小文件尺寸的任务
grunt-contrib-watch:一个检测文件活动的任务
首先,创建信的空的Web应用程序添加示例的Typescript文件,Typescript文件在Visual Studio 2015的默认设置下,会自动地编译为Javascript中并且作为Grunt的源文件。
enum Tastes { Sweet, Sour, Salty, Bitter }
class Food { constructor(name: string, calories: number) { this._name = name; this._calories = calories; } private _name: string; get Name() { return this._name; } private _calories: number; get Calories() { return this._calories; } private _taste: Tastes; get Taste(): Tastes { return this._taste } set Taste(value: Tastes) { this._taste = value; } }
下一步,配置npm来下来grunt和grunt-tasks
这些包将会被自动下载,你可以在node-modules目录下看到下载的内容,前提是你打开了”显示所有文件“
如果需要的话,你要可以通过右键单击dependences下的NPM,选择Restore Packages按钮恢复这些包
Grunt使用名为gruntfile.js的文件清单进行配置、加载和注册任务,让它可以手动的运行或者基数Vistual Studio的事件机制自动运行
module.exports = function (grunt) { grunt.initConfig({ }); };
module.exports = function (grunt) { grunt.initConfig({ clean: ["wwwroot/lib/*", "temp/"], }); };
grunt.loadNpmTasks("grunt-contrib-clean");
module.exports = function (grunt) { grunt.initConfig({ clean: ["wwwroot/lib/*", "temp/"], }); grunt.loadNpmTasks("grunt-contrib-clean"); };
module.exports = function (grunt) { grunt.initConfig({ clean: ["wwwroot/lib/*", "temp/"], concat: { all: { src: ['TypeScript/Tastes.js', 'TypeScript/Food.js'], dest: 'temp/combined.js' } }, }); grunt.loadNpmTasks("grunt-contrib-clean"); };
jshint: { files: ['temp/*.js'], options: { '-W069': false, } }
uglify: { all: { src: ['temp/combined.js'], dest: 'wwwroot/lib/combined.min.js' } },
module.exports = function (grunt) { grunt.initConfig({ clean: ["wwwroot/lib/*", "temp/"], concat: { all: { src: ['TypeScript/Tastes.js', 'TypeScript/Food.js'], dest: 'temp/combined.js' } }, jshint: { files: ['temp/*.js'], options: { '-W069': false, } }, uglify: { all: { src: ['temp/combined.js'], dest: 'wwwroot/lib/combined.min.js' } }, }); grunt.loadNpmTasks("grunt-contrib-clean"); grunt.loadNpmTasks('grunt-contrib-jshint'); grunt.loadNpmTasks('grunt-contrib-concat'); grunt.loadNpmTasks('grunt-contrib-uglify'); };
使用grunt.registerTask方法来注册运行一系列指定顺序的任务,比如,运行上文中任务的顺序应该为clean->concat->jshint->uglify。在文件中添加以下代码,并且保持方法调用和loadNpmTasks调用时同级的
grunt.registerTask("all", ['clean', 'concat', 'jshint', 'uglify']);
现在你可以在Task Runner Explorer中找到一个名为all的别名任务,运行它即可顺序执行上文中的所有任务了
Watch任务可以监视文件和目录的变化,并且在监测到变化后触发一系列任务,在initConfig方法中添加以下的代码来监视Typescript目录下的所有js文件的变化,并执行’all“任务
watch: { files: ["TypeScript/*.js"], tasks: ["all"] }
添加一个loadNpmTask方法调用让任务显示在Task Runner Explorer中
grunt.loadNpmTasks('grunt-contrib-watch');
运行Watch任务,命令行窗体将处在等待状态,此时它监视着文件的变化,打开一个Typescript文件,添加任何内容,你就会发现它已经在工作了
你除了可以手动运行这些任务之外,你还可以把这些任务和Visual Studio事件绑定,当Visual Studio触发既定的事件后,自动运行定义的任务
在Task Runner Explorer中,右键点击watch任务,选择“Bindings->Project Open”,此时,当你打开项目的时候,watch任务将自动执行并且观测文件变化并执行上文中定义的一系列任务
除了一些著名的不同以外,Gulp的配置文件和grunt的非常相似,下文中的例子对比grunt的示例但是使用gulp包和约定。
与grunt一样,gulp定义也在ackage.json文件的devDependencies属性中,内容如下文所示,你也可以通过只能提示来更新到最近的版本号。
{ "version": "1.0.0", "name": "GruntFromEmptyWebApp", "private": true, "devDependencies": { "gulp": "3.8.11", "gulp-clean": "0.3.1", "gulp-jshint": "1.11.0", "gulp-concat": "2.5.2", "gulp-uglify":"1.2.0", "gulp-rename": "1.2.2", "gulp-watch": "4.2.4" } }
取代gruntfile.js,添加一个命名为gulpfile.js的文件,在这个文件中,使用node.js的方法require()为下文中的几个变量赋值
var gulp = require('gulp'); var clean = require('gulp-clean'); var concat = require('gulp-concat'); var jshint = require('gulp-jshint'); var uglify = require('gulp-uglify'); var rename = require('gulp-rename'); var watch = require('gulp-watch');
在赋值语句下方,调用gulp的task方法,第一个参数是任务的名字的字符串表示方式,第二个参数是一个回调方法
gulp.task('default', function () { // place code for your default task here });
此时在Task Runner Explorer中已经存在一个命名为default的任务,虽然它是空的
在task方法的回调函数内部,使用方才定义的gulp执行我们需要的工作,首先定义一个clean任务
gulp.src('wwwroot/lib/*').pipe(clean());
gulp是一个包含src、pipe和dest方法的流式对象
代码通常的模式如下文所示
gulp.src() .pipe() .pipe() .pipe(dest());
src方法拿到初始的原始流文件,在一系列的pipe调用后执行对流的操作,最后通过dest()方法输出最终的结果,这种方式的优势是只有一个输入和一个输出,让任务执行的更快。
下文是我们组织的一系列任务,将它定义为ALL,执行的任务和上文中grunt的例子是完全一样的
gulp.task("all", function () { gulp.src('wwwroot/lib/*').pipe(clean()); gulp.src(['TypeScript/Tastes.js', 'TypeScript/Food.js']) .pipe(concat("combined.js")) .pipe(jshint()) .pipe(uglify()) .pipe(rename({ extname: '.min.js' })) .pipe(gulp.dest('wwwroot/lib')) });
watch任务也和grunt的示例非常相似
gulp.task("watch", function () { gulp.watch("TypeScript/*.js", ['all']); });
使用同样的方式,在Task Runner Explorer中绑定Visual Studio事件,就可以让watch任务在项目打开时自动执行了。
原文链接: http://docs.asp.net/en/latest/client-side/grunt-gulp.html