requirejs之局部require函数踩坑

最近用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}));
});

希望此文章对大家有所帮助。

你可能感兴趣的:(requirejs之局部require函数踩坑)