ERROR in static/js/0.705716c542478b712e7e.js from UglifyJs Unexpected token: punc-分析打包过程可能遇到的报错
在webpack3升级webpack4过程中,项目原有uglifyjs-webpack-plugin版本为v1.0.0。但升级后uglifyjs-webpack-plugin版本已不合适,因为v1.2.1以下的版本依赖的webpack版本为2.x或3.x,如下图:
后面直接升级到2.x。没意识到版本升级的坑,一直在其他地方排查错误。
查原因是uglifyjs不支持es6的压缩,后面发现2.x的版本不再支持es6的压缩才理解,如下图:
图来源地址:https://github.com/webpack-contrib/uglifyjs-webpack-plugin/blob/master/CHANGELOG.md
找到问题,准备安装这个插件:terser-webpack-plugin, 顺手查了下webpack4自带这个插件,直接引用,问题解决
顺手又查了下版本记录:发现v1.2.2 - v2.0.0的版本支持webpack4压缩es6,如下图:
故遇到此类问题,想压缩插件支持压缩es6, 优先查看当前项目是否引用uglifyjs-webpack-plugin。
- 如果webpack版本为3.x, 则使用版本uglifyjs-webpack-plugin为1.x版本都可(支持es6的压缩)
- 如果webpack版本为4.x, 则使用webpack4内置terser-webpack-plugin 或 uglifyjs-webpack-plugin v1.2.2-v2.0.0之间的版本(支持es6的压缩)
后续:
用以上的方法解决了打包的报错,可是心中留下了疑问, uglifyjs-webpack-plugin2.x的版本出现的目的是为了解决什么?
原有的认知以为到了压缩这一步,觉得代码都已转译为es5,实际并非如此。而这个漏洞大部分来源于node_modules中的npm包。比如我们引入npm包质量不够高,含有es6语法,那么只支持压缩es5的插件在打包压缩过程中就会报错。
对于需要兼容低版本的浏览器基于只支持压缩es5的混淆压缩插件十分友好,让开发者在本地打包就可以发现问题,避免了在一些低版本浏览器因为不支持es6语法导致界面报错。
so, 决定用只支持es5的压缩插件进行测试,于此同时分析打包过程中报错产生的原因有哪些(以vue框架,babel7举例):
1)观察bableRc基本预设和插件是否都配置对,还有JSX的支持,导致不能正常编译(即npm run dev都报错)
{ "presets": [ ["@babel/preset-env", { "modules": false, "targets": { "browsers": ["> 1%", "last 2 versions", "not ie <= 8"] } }] ], "plugins": ["@babel/plugin-syntax-jsx", "@babel/plugin-transform-runtime"], "env": { "development":{ "plugins": ["dynamic-import-node"] } } }
上述确认通过后,继续测试。我们传统的认知babel就是将es6转换为浏览器可识别的es5,但往往忽视了BabelRc文件设置的targets属性,假如我们配置浏览器为chrome的最新两个版本,自然而然最后得到的打包结果是含有es6,即对于环境支持的语法是不做转换的。
2)去除targets相关属性测试
{ "presets": [ ["@babel/preset-env"] ], "plugins": ["@babel/plugin-syntax-jsx", "@babel/plugin-transform-runtime"], "env": { "development":{ "plugins": ["dynamic-import-node"] } } }
如果不报错,就需要调整浏览器的范围配置。打包结果如果依旧报错,则排除是targets导致,那接着往下排查
3)观察报错提示
首先记下报错的行数,然后屏蔽压缩插件,重新打包,此时得到的打包文件是未经压缩,方便查看是哪个模块报错:如下图,
4)通过上图报错信息得知是UI框架:以element-ui引入举例
网上查资料大部分描述都是我们引入的npm包可能是es6包,所以需要在:bable-loader处包含node_modules的相关报错模块,如下图所示:
结果是报错一动没动,奇了怪了,这是个头疼的疑点。然后我又去找打包文件,发现同样的代码打包了两次,一次已转译,一次未转译。
我晕了,然后想难道是重复打包的相关知识点。查找未果后,又去看node_modules下面的element-ui包:
发现如下图所示:/lib下面都是转译的代码,其他都未转译的代码。
直击灵魂的怀疑:难道是项目内组件或方法引用出了路径有问题,全局搜索element-ui最后找到两处:
1 组件引用地址不合乎规范(ElSwitch组件引用)
项目内:
import ElSwitch from 'element-ui/packages/switch/src/component' (这些路径都是element-ui的源代码,都是es6)
应调整为:
import { ElSwitch } from 'element-ui' (这种默认格式其实都是取的element-ui/lib下的转译结果)
2 引用的方法路径不正确
项目内:
import scrollIntoView from 'element-ui/src/utils/scroll-into-view'
应调整为:
import scrollIntoView from 'element-ui/lib/utils/scroll-into-view'
虽然这些报错也可在babel-loader处配置转译解决(我配置了未生效。。。下面我会解释未生效的原因):但是我觉得应该从源头上就调整,不仅可以减少重复打包,而且不用在配置文件配这些不好看的格式。除非是其他情况不可避免。
5)上面Element的报错是解决了,遗留的问题是我的bableRc配置为什么会对node_modules的转译不生效
查了相关资料后给出的答案是babel7的版本问题,对于babel7,应使用babel.config.js配置相关预设和插件,而不是babelRc。其实大部分资料都说的这几种配置都可行。
抱着试试的心态,我删除了我的babelRc文件,添加babel.config.js文件。结果能正常转译;配置文件如下:
module.exports = function(api) { api.cache(true); const presets = [ ["@babel/preset-env", { "modules": false, "targets": { "browsers": ["> 1%", "last 2 versions", "not ie <= 8"] } }] ]; const plugins = [ ["import", {"libraryName": "vxe-table", "style": true}], "transform-vue-jsx", "@babel/plugin-syntax-dynamic-import", ["@babel/plugin-transform-runtime", { "corejs": 3 }] ]; return { presets, plugins } }
至此打包报错的问题基本分析到这里了。感想就是因为插件,预设更新的比较频繁,很多东西稍微一动,就发现这里报错,那里报错。不过也不用慌。关注报错信息,一步一步慢慢解决。