公司老项目,使用的是webpack 3.X 构建项目。没有升级的打算。这个项目在本地 build 的时候,打包成功。但是到了GitLab CI/CD 或 Docker 中,却 build 失败。失败原因是:
ERROR in main_25188b.js from UglifyJs
Unexpected token: name (raf) [main_25188b.js:121200,4]
不知道是什么原因,本地环境能够正常 build,但是一到了 linux 环境就会 build 失败。尝试了很多方法,没能够拿到 GitLab 或 Docker build 后的代码,拿不到 main_25188b.js 文件,就一直无法从这个文件里查看是哪里的代码出现问题。
报错很明显提示是UglifyJs
出了问题,由于 uglifyjs 无法处理 es6 语法,导致报错
,但是我的项目package.json里没有安装 UglifyJs
依赖包。本地的部分 package.json 配置如下:
{
// ... ... 省略部分代码
"devDependencies": {
"autoprefixer": "^7.1.6",
"babel-core": "^6.26.0",
"babel-loader": "^7.1.2",
"babel-polyfill": "^6.0.16",
"babel-preset-env": "^1.6.1",
"babel-preset-es2015": "^6.0.15",
"babel-preset-latest": "^6.24.1",
"babel-preset-stage-0": "^6.0.15",
"copy-webpack-plugin": "^4.6.0",
"copy-webpack-plugin-advanced": "^2.0.0",
"css-loader": "^0.28.7",
"extract-text-webpack-plugin": "^3.0.2",
"file-loader": "^1.1.5",
"html-loader": "^0.5.5",
"html-webpack-plugin": "^2.30.1",
"postcss-import": "^11.0.0",
"postcss-loader": "^2.0.8",
"sass": "1.53.0",
"sass-loader": "^7.3.1",
"style-loader": "^0.19.0",
"url-loader": "^0.6.2",
"vue-loader": "^13.5.0",
"vue-style-loader": "^3.0.3",
"vue-template-compiler": "^2.5.3",
"webpack": "^3.8.1",
"webpack-md5-hash": "^0.0.5"
},
"dependencies": {
"archiver": "^5.3.1",
"cross-env": "^7.0.3",
"echarts": "^4.1.0",
"js-base64": "^2.3.2",
"lodash.merge": "^4.6.2",
"qrcode": "^1.5.3",
"qs": "^6.11.2",
"ts-md5": "^1.2.7",
"vue": "^2.5.3",
"vue-echarts": "^4.0.1",
"vue-i18n": "^8.24.4",
"vue-resource": "^1.3.4",
"vue-router": "^3.0.1",
"vue-touch": "^2.0.0-beta.4"
}
}
通过vscode的全局搜索发现有不少依赖包里使用了 UglifyJs 。
这种情况,就没法通过将 UglifyJs
替换为 babili-webpack-plugin
插件来解决。
检查项目的 webpack.config.js 文件,找到 babel-loader 处理的部分。
// 省略大量代码
var path = require('path');
function resolve (dir) {
return path.join(__dirname,dir);
}
module.exports={
module:{
rules:[
// 处理.js文件(把ES6语法转义)
{
test:/\.js$/,
loader:'babel-loader',
exclude:__dirname+'/node_modules/',
query:{
presets:['es2015', "stage-0"]
},
},
],
}
}
看到这里,发现 babel-loader 在编译代码的时候,exclude:__dirname+'/node_modules/'
,排除了node_modules
文件的编译。当我把这个 exclude 删掉后,使用 GitLab 或 Docker 的环境去 build ,结果 build 成功。
由此可见,是node_modules
中某个 js 文件使用了 es6 语法,没有编译成 es5 ,导致 UglifyJS 编译出错。
将node_modules所有文件都丢进 babel-loader 编译一遍是不现实的,大大浪费编译时间。所以我们是哪个依赖包出了问题。
只需要找出是哪个依赖包的 js 文件没有编译为 es5 ,将这个依赖包 include 进 babel-loader 中,就可以解决这个问题。
那么要如何找呢?
我们将 exclude 排除 node_modules 编译,改为 include 仅包含 xxx 文件编译。
// 省略大量代码
var path = require('path');
function resolve (dir) {
return path.join(__dirname,dir);
}
module.exports={
module:{
rules:[
// 处理.js文件(把ES6语法转义)
{
test:/\.js$/,
loader:'babel-loader',
include:[
resolve('dist/'),
],
query:{
presets:['es2015', "stage-0"]
},
},
],
}
}
执行 npm run build
后,复现了 GitLab CI/CD 或者 Docker 中 build 出现的错误。
借助VScode 的跳转功能,按住 Ctrl + 鼠标移动
到报错位置,报错的地方就会出现下划线,在按住 Ctrl
的同时,鼠标左键
点击报错的地方,就可以跳转到报错的代码处。
VS Code 搜索配置:
第一行 搜索内容:取消 Aa
ab
.*
的筛选
第三行 包含的文件:清空,不要有任何字符或空格,如果有很明确的报错地方,也可以将该文件夹的名称写上去,如果确定就是node_modules报错,可以写上./node_modules
第四行 排除的文件:不要点亮
这个排除按钮,不使用“排除设置与忽略文件”
做好上述的配置后,搜索在 main_25188b.js 找到的导致报错的代码:
搜索的结果是:在 node_modules\resize-detector
中,有es6代码没有被编译为 es5。
注意
:如果搜索的代码是 let name = null;
烂大街到处都有的那种代码,可以在 main_25188b.js 的错误代码附近,找
一个自己看起来 变量名比较独特的代码
进行搜索
。
// 省略大量代码
var path = require('path');
function resolve (dir) {
return path.join(__dirname,dir);
}
module.exports={
module:{
rules:[
// 处理.js文件(把ES6语法转义)
{
test:/\.js$/,
loader:'babel-loader',
include:[
resolve('dist/'),
resolve('node_modules/resize-detector/esm/')
],
query:{
presets:['es2015', "stage-0"]
},
},
],
}
}
ok,重新 npm run build
下。噢!天哪!又报错了!
还是UglifyJS 报错,好的,按照上述方法定位查找是哪个node_modules又搞事情。
哦,是node_modules/qrcode/lib/
这个小妖精,把它加到 include 里
// 省略大量代码
var path = require('path');
function resolve (dir) {
return path.join(__dirname,dir);
}
module.exports={
module:{
rules:[
// 处理.js文件(把ES6语法转义)
{
test:/\.js$/,
loader:'babel-loader',
include:[
resolve('dist/'),
resolve('node_modules/resize-detector/esm/'),
resolve('node_modules/qrcode/lib/'),
],
query:{
presets:['es2015', "stage-0"]
},
},
],
}
}
重新 npm run build
下,OK,这次终于没有报下面这种错误了。
ERROR in main_96f20a.js from UglifyJs
Unexpected token: name (toSJISFunction) [main_96f20a.js:35061,4]
可喜可贺。
include:[]里,要加上需要将 es6 转为 es5 的所有文件,可以使用目录,也可以写具体某个js文件
最后发现,原来是 package.json
中添加的 qrcode
这个插件导致的错误。
如果项目之前能够正常npm run build
,但是加了某个依赖后,npm run build
失败了。可以猜测是那个依赖本身有问题,或是这个依赖的依赖有问题。快速定位到问题。