問題背景
最近做了一個webapp項目,qa用手機測試功能時,在iphone6plus上表現是白屏,其他手機目測是ok的;因為之前在測試其他項目時也發現在這個iphone6上表現與其他手機不太一樣。於是當時以為這個手機出了什么問題,或者其版本過低;就不放在心上。
然而這次白屏的影響還是要加以重視,於是在空閑的時候主動看了下,用VSCosole
查看了日志信息,控制台報了一個警告信息:
unexception token const ...
然后看了加載的js源碼,竟然發現一個大坑:
-
代碼沒有壓縮
-
部分代碼也沒有編譯成es5
這時心里頓生一陣陣的涼意,辛虧看了一下這個問題,否則發到線上會有重大問題。
uglifyjs為啥會報錯
出現上面的問題,首先會想到的webpack的壓縮代碼插件出問題了,項目中使用uglifyjs-webpack-plugin
來壓縮代碼。於是在本地執行發布上線的操作代碼編譯壓縮,果不其然,壓縮類似這樣的錯誤:
ERROR in static/javascripts/test_0_30fbc92.js from UglifyJs
Unexpected token: name (instance) [static/javascripts/test_0_30fbc92.js:2854,6]
具體可以看下圖:
然后定位到指定文件的報錯的位置,發現都是es6的語法:
-
第一個文件2874行的內容:
let instance
-
第二個文件78行的內容:
function loadJS(url, {timeout = 5000, crossOrigin = false } = {}) {
可以看到,這兩個位置都是文件第一次出現es6沒有編譯的位置,其實在此之后還有很多未編譯的es6語法。
可能到這里有人會問,上面壓縮報錯為什么還能在非iphone6p的其他手機上可以正常訪問到呢,可能原因如下:
-
uglifyjs-webpack-plugin雖然報錯但是並不會阻止代碼的產出,從上圖也可以看出代碼已經產出。只不過其內容沒有壓縮
-
另一個原因我猜是未出現問題的手機上打開瀏覽器已經支持這些es6語法
分析了這么多,為啥uglifyjs-webpack-plugin會報錯呢,因為當前引用uglifyjs-webpack-plugin的版本為0.4.6
,它依賴的是uglify-js
; 它不支持壓縮 es6,可以參考github的issueIt seems like uglify-js does not support es6?。
所以:
uglify-js在壓縮代碼時,遇到es6語法就不會壓縮並且也會報錯。
如果想壓縮e6代碼,可以使用uglify-es
,其提供配置屬性ecma
來壓縮不同類型的js。
es6為啥沒有編譯
上面分析我們得知,uglify-webpack-plugin之所以沒有壓縮,因為代碼混合es6語法,那么es6語法為啥沒有編譯呢?推測:
在使用babel來編譯es6時,由於webpack錯誤配置的原因導致某些文件不在指定的babel編譯范圍,babel從而會忽略這些js文件的編譯
我們的項目目錄結構如下:

這是個多個微系統共用的一個工程,這些微系統共用的組件大部分相同,他們共用一個webpack配置。
webpack的有關js的配置如下所示:
{
test: /\.js$/,
loader: 'babel-loader',
include: [
path.resolve('moudleA'),
path.resolve('moudleB')
]
}
但是與服務端交互的api目錄、公共組件components目錄以及公共的js方法目錄common目錄沒有配置進上面babel-loader的include數組中,從而babel-loader會忽略這些目錄下的js文件編譯,導致這些目錄下的js文件沒有被babel-loader編譯。從而導致上述問題。
所以,總結一下:
開發過程中遇到任何問題還是需要認真對待一下,保持一顆這就是bug的心態去發現並找出原因所在,才能降低線上出現重大問題的風險。