最近用gulp压缩了一下requirejs项目中的文件,出现了让人很纠结的错误,原代码
define(funciton(require){ var $ require = $("jquery");});
压缩后:
define(function(n){var $ = n("jquery")});报错:Uncaught Error: Module name "jquery" has not been loaded yet for context
可以看到压缩前后唯一的区别就是,函数名require被替换了更精简的n。讲道理require作为一个形参,叫啥名字应该都没关系的,可偏偏就出了错。
更神奇的是只要将函数内部的n改成require就不报错了:define(function(n){var $ = require("jquery")});
蛋疼,明明传进来的是n,哪来的require啊。
虽然局部require只是requirejs的一个语法糖,但没道理压缩后就会报错啊。一番搜索后终于找到原因。根据局部require最终会被转化为define([])形式,但是转化的方法比较特殊,是通过Function.prototype.toString()来获取依赖值的。问题就出在这个Function.prototype.toString()方法上,它将整个回调函数转成了string,然后在string中通过"require"字符串来寻找依赖。所以,局部require不能被替换成其它名字,而且require()中不能放变量或者path,因为转成字符串后可识别不出这些。其实,在执行Function.prototype.toString()前会执行另一个方法,参考得知,首先会执行unction.prototype.length来判断回调函数中有几个参数,1个参数时就认为传入了require,2个参数时就认为传入了require和exports,3个参数时认为传入了require,exports和module。这也是为什么define(function(n){var $ = require("jquery")});
能够正常运行的原因。
官网推荐的解决办法是全改成常规的define([])来定义依赖。我目前的做法是配置gulp不压缩name:var uglify = require("gulp-uglify");gulp.task("default",function(){ gulp.src(path).pipe(uglify({mangle:false}));});
希望此文章对大家有所帮助。