Grunt 实例之 实现js合并、压缩、生成Source map文件

随着前端各个技术的蓬勃发展和 对页面性能的越来越重视,我们前端不仅仅要写得一手好的代码,同时还要使用各种的自动化工具来对代码进行 压缩、合并,控制页面的请求数 与 体积。

在没有自动化工具的年代,我们只能手动把js 合并、再通过js 压缩工具将js压缩,效率可想而知的低,而且如果遇到问题 需要调试就各种痛不欲生了。。

所以说生活在有自动化开发工具年代的鞋子都是幸福的。。

在这里介绍的是 如何利用 grunt 对 js 进行 合并压缩并生成 sourceMap,在最大程度压缩页面的同时,也不影响页面的 可维护性。

在讲实际操作之前,我们先了解一下理论知识。

Source map

jquery 1.11.0 开始标识 Source map 的注释 已经不在 压缩文件里面,要手动加上才有,在这里我们以 1.9.0 版本作为例子

访问 http://ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js 打开压缩后的版本,滚动到底部,你可以看到最后一行是这样的:

//@ sourceMappingURL=jquery.min.map

这就是Source Map。它是一个独立的map文件,与源码在同一个目录下,你可以点击进去,看看它的样子。

http://ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.map

这是一个很有用的功能,下面将详细讲解这个功能。

从源码转换讲起

JavaScript脚本正变得越来越复杂。大部分源码(尤其是各种函数库和框架)都要经过转换,才能投入生产环境。常见的源码转换,主要是以下三种情况:

  • 压缩,减小体积。比如jQuery 1.9的源码,压缩前是252KB,压缩后是32KB。
  • 多个文件合并,减少HTTP请求数。
  • 其他语言编译成JavaScript。最常见的例子就是CoffeeScript。

这三种情况,都使得实际运行的代码不同于开发代码,除错(debug)变得困难重重。

通常,JavaScript的解释器会告诉你,第几行第几列代码出错。但是,这对于转换后的代码毫无用处。举例来说,jQuery 1.9压缩后只有3行,每行3万个字符,所有内部变量都改了名字。你看着报错信息,感到毫无头绪,根本不知道它所对应的原始位置。

这就是Source map想要解决的问题。

什么是Source map

简单说,Source map就是一个信息文件,里面储存着位置信息。也就是说,转换后的代码的每一个位置,所对应的转换前的位置。有了它,出错的时候,除错工具将直接显示原始代码,而不是转换后的代码。这无疑给开发者带来了很大方便。

目前,暂时只有Chrome浏览器支持这个功能。在Developer Tools的Setting设置中,确认选中”Enable source maps”。默认是激活此功能的

map文件不会对页面增加额外的请求,只有在调用浏览器调试工具的时候(这里说的是 chrome)才会加载进来。

如何启用Source map

正如上面所提到的,只要在转换后的代码尾部,加上一行就可以了。

//@ sourceMappingURL=/path/to/file.js.map

map文件可以放在网络上,也可以放在本地文件系统

如何生成Source map

咳,其实这个才是本文的主题,我们可以通过 grunt 的 grunt-contrib-uglify 插件来实现 合并、压缩、生成 Source map。

grunt-contrib-uglify

uglify 插件的压缩 我们经常使用,但是 查看 他的 妈蛋文件 原来 还支持 生成 Source map 文件,这虽是情理之中,却在意料之外,

下面先来一发简单的例子

module.exports = function(grunt) {
	// 项目配置
	grunt.initConfig({
		pkg: grunt.file.readJSON('package.json'),
		uglify:{
			"demo":{
				options: {
					// 放在生成后的压缩文件的头部注释文案
					banner: '/*! builded <%= grunt.template.today() %> */\n',
					// 生成的map文件地址与源文件(src/1.js)的 相对路径
					sourceMapRoot: '../../',
					// 生成 map文件的地址
					sourceMap: 'dist/map/mix.map',
					// 用于定义 map文件地址 并放在压缩文件底部, url相对于 压缩文件(dist/mix.js)
					sourceMappingURL: 'map/mix.map'
				},
				files:{
					"dist/mix.js":["src/1.js","src/2.js"]
				}
			}
		}
	});
	// 加载提供"uglify"任务的插件
	grunt.loadNpmTasks('grunt-contrib-uglify');
	// 注册任务
	grunt.registerTask('default', ['uglify']);
}

例子 demo: http://www.jackness.org/lab/2014/grunt_uglify/grunt_uglify.zip

其中, uglify插件 option选项中的 sourceMap、sourceMappingURL 还可以是 一个 函数,下面是 如果把 sourceMap、sourceMappingURL 赋值成 function

grunt.initConfig({
	pkg: grunt.file.readJSON('package.json'),
	uglify:{
		"demo":{
			options: {
				// 放在生成后的压缩文件的头部注释文案
				banner: '/*! builded <%= grunt.template.today() %> */\n',
				// 生成的map文件地址的 相对路径
				sourceMapRoot: '../../',
				// 生成 map文件的地址
				sourceMap: function(path){
					var f = path.split("/"),
						filename = f.pop(),
						nav = f.join("/") + "/";
					return nav + "map/" +  filename.replace('.js','.map');
				},
				// 用于定义 map文件地址 并放在压缩文件底部, url相对于 压缩文件
				sourceMappingURL: function(path){
					var f = path.split("/"),
						filename = f.pop(),
						nav = f.join("/") + "/";
					return "map/" +  filename.replace('.js','.map');
				}
			},
			files:{
				"dist/mix.js":["src/1.js","src/2.js"]
			}
		}
	}
});

其中 path 指的是 需要映射的压缩文件名 (dist/mix.js)

例子 demo: http://www.jackness.org/lab/2014/grunt_uglify/grunt_uglify_fn.zip

安装例子之后 执行 grunt 进行文件压缩

grunt

然后打开 压缩包种的 demo文件可以看到 错误能正确指向 1.js 文件

我来评几句
登录后评论

已发表评论数()

相关站点

+订阅
热门文章