Sourcemap 这个单词也时不时出现在我们眼里,今天就来学习它。其实有时候学习一些概念并不是很刻意地去学习,而是遇到了问题,发现了这里有个解决方案,就把它给学了。

那么,Sourcemap 解决了什么呢?

# 问题背景

上一节中,我们已经基本学会怎么把 es6 的代码转化为 es5,那假设我在 b.js 中,刻意制造一些错误。

let words = "cat";
let error = "i am a " + message; // 未定义的变量
export {words};

接着记得使用 browserify a.js -o a_bundle.js -t [babelify --presets[env]] 编译一下代码。

补充一下,我使用的浏览器是 chrome 浏览器。

尝试打开页面之后会发现浏览器报错了:

很明显,浏览器找到了你使用了未定义变量 message 的错误。

但是我们会发现一个问题:浏览器定位错误的时候,定位的是打包后的那个 a_bundle.js 。可以看到上图中定位到了这个文件的第 25 行,在日常的开发中我们很经常看了行号就回去修改 bug 了。然而,我们开发的时候并不是使用这个 a_bundle.js 进行开发,所以这个定位对于我们没有什么用呀。

Q:这个例子中直接回去改 b.js 不就完了= =? A:在日常的开发中,脚本文件一多,一不小心在哪里敲多了个符号,然后全部脚本都被拼接到 bundle.js 里面,一旦浏览器报错,定位的行号却只是 bundle.js 的行号而不是具体到哪一个脚本的行号,导致不知道如何修改自己的代码错误。在例子中只是刻意制造一种出错的情况。

在很久之前其实我也写过和 Gulp 相关的文章了。

但是这一次不一样,我们是带着一些痛点来学习的。

# 问题背景

前两节里面我们经常使用以下命令行代码来转化 es6 至 es5

browserify a.js -o a_bundle.js -t [babelify --presets[env]] -d

这样子有一个很不方便的地方,就是每一次都修改了代码都得重新运行一次以上代码生成 a_bundle.js

改完要运行一次改完要运行一次改完要运行一次,真麻烦!

# Gulp

然而我们这一次要学会使用 Gulp,它能够做的事情很多,但是在这一篇里面我只尝试告诉你:

它能够实时监控你的代码,一旦你的代码发生变化(当你 Ctrl+S 保存的时候),Gulp 就会自动帮你运行本文开头的那句命令。

是不是很期待?那我们一边做一边理解吧~

首先我们得通过 npm install gulp 来安装它。

然后在我们之前一直在用的项目目录里面新建一个文件名字叫做 gulpfile.js

首先要说明一下,这个文件并不是我们日常生活中接触的那些被 html 引入的 js 文件。 而且这个文件的文件名 gulpfile 也不是随便起的,我们就按照Gulp的约定来命名这个文件。 就如同第一节中,我们使用 babel 的时候建立了一个 .babelrc 文件。

大家会发现,前两节中我们很经常安装了某一个工具(babel,browserify)就直接在命令行里使用,gulp 也一样,同时,它还需要一个 gulpfile.js 作为它的配置文件。

# Gulpfile.js

现在,我们为了完成我们的约定,打开 gulpfile.js 并输入以下内容:

var gulp = require("gulp");
var browserify = require("browserify");
var babelify = require("babelify");
var source = require('vinyl-source-stream');

gulp.task('bundle', function(){
  return browserify('./a.js',{debug: true})
         .transform(babelify,{presets:['env']})
         .bundle()
         .pipe(source('a_bundle.js'))
         .pipe(gulp.dest('./'));
});

现在先自己分析一下上面写的这串代码,尝试看懂它,我们会发现在一开始的地方 require 进来了 4 个库。 而这 4 个库中,我们好像已经安装了前三个,因为我们之前通过 npm install 安装到了 node_modules 里面去了。

所以我们还需要运行 npm install vinyl-source-stream 来安装这个鬼东西。

如果你是跟着我前面几篇文章一起操作的话,那么现在我们是可以在命令行里面成功执行这一句的:

gulp bundle

执行结果如下图所示:

我们刚刚写的 gulpfile.js 就是为了让执行 gulp bundle 的效果和文章一开头那句的效果一样:

browserify a.js -o a_bundle.js -t [babelify --presets[env]] -d

你可以理解为我是换了一种语法而已,那怎么理解它呢?

首先在命令行里面使用 gulp ,它后面跟着的东西是一个任务名称,上述命令中的任务名称叫做 bundle

而这个 bundle 任务是我自己编写出来的,体现在了 gulp.task() 的第一个参数里面。

它的第二个参数,是指命令的具体运行内容。你会发现我们在其中使用了 browserify() 函数,这个函数的一些具体的使用方法可以在它的官网中查到。

那我再注释一下上面的代码,具体的就不扩展开来讲了,详细可以参考我写过的入门文章

gulp.task('bundle', function(){ //定义一个 bundle 任务
  return browserify('./a.js',{debug: true}) //使用 browserify 取得 a.js 并且开启 debug 以生成 sourcemap
         .transform(babelify,{presets:['env']}) 
          //使用 browserify.transform() 进行代码转换,
          //这其中使用了 babelify 作为转换工具,并且使用了 env预设。
         .bundle() //拼接打包成一个文件
         .pipe(source('a_bundle.js')) //为这个刚刚拼接好的文件取一个名字
         .pipe(gulp.dest('./')); //输出到当前文件夹
});

现在,我们再为这个 gulpfile.js 添加两个新的任务:monitor,default

  • monitor:用于监视代码有没有发生变化及操作
  • default:整合 bundle + monitor ,让你更加偷懒。

所以现在我们的 gulpfile.js 如下:

var gulp = require("gulp");
var browserify = require("browserify");
var babelify = require("babelify");
var source = require('vinyl-source-stream');

gulp.task('bundle', function(){
  return browserify('./a.js',{debug: true})
         .transform(babelify,{presets:['env']})
         .bundle()
         .pipe(source('a_bundle.js'))
         .pipe(gulp.dest('./'));
});

gulp.task('monitor',function(){
    gulp.watch("./a.js",['bundle']);
});

gulp.task('default',['bundle','monitor']);

现在,当我们要接着改这个项目的时候,直接在命令行里面输入四个字母就行了: gulp

你会看到它同时执行了两个任务,一个是 bundle,一个是 monitor。而 bundle 帮我们打包完文件就执行完毕了,后面的 default 执行和结束我们并不需要管它。

我们关注的是这个命令好像并没有执行完毕一样,没有出现让我输入下一句命令的光标。 这就对了,只要我们不关闭命令行工具,它就会一直帮我们监视着 a.js 这个文件。

现在我们尝试着修改 a.js ,保存后观察命令行工具:

(命令行:检测到变化!现在开始执行bundle!)

所以,只需要运行一句 gulp ,我们就再也不用管其他什么鬼命令了,真棒!

# 总结

基本上可以说,到目前为止我们已经掌握了一些非常有用的东西了,用着现在拥有的知识已经可以搞搞搞很多事情了,甚至还可以继续深入我们的学习,把新的知识用起来吧!