requirejs之局部require函數踩坑

最近用gulp壓縮了一下requirejs項目中的文件,出現了讓人很糾結的錯誤,原代碼html

define(funciton(require){
    var $ require = $("jquery");
});

壓縮後:jquery

define(function(n){var $ = n("jquery")});
報錯:Uncaught Error: Module name "jquery" has not been loaded yet for context

能夠看到壓縮先後惟一的區別就是,函數名require被替換了更精簡的n。講道理require做爲一個形參,叫啥名字應該都不要緊的,可恰恰就出了錯。
更神奇的是隻要將函數內部的n改爲require就不報錯了:git

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。這也是爲何github

define(function(n){var $ = require("jquery")});

可以正常運行的緣由。
官網推薦的解決辦法是全改爲常規的define([])來定義依賴。
我目前的作法是配置gulp不壓縮name:gulp

var uglify = require("gulp-uglify");
gulp.task("default",function(){
    gulp.src(path).pipe(uglify({mangle:false}));
});

但願此文章對你們有所幫助。api

相關文章
相關標籤/搜索