YUICompressor 是一个优秀的js&css的压缩工具。系统使用其2.4.8版本的jar压缩css和js。开发阶段一切正常,但部署到测试环境和线上环境后,js压缩失败,报IndexOutOfBoundsException。
看了下其逻辑,大致是先将待压缩的文本做预处理:识别文本中的function关键字、语句等特征部分,插入一些这些特征部分的标识符和长度信息;再根据这些信息构建压缩后的文本。比对了下测试环境和开发环境中预处理后的文本,发现测试环境中预处理后的文本在最末尾处的长度信息有误,导致substring的endIndex超出了文本长度。
测试环境和开发环境,源文本唯一的差别是字符串连接时使用的折行符,windows是回车换行,linux是回车,但经验判断不太可能是这个原因导致的。系统排除折行符的差异后,对比预处理后的文本字节码,发现字节码有差异。从源代码逻辑里,无法猜测导致差异的原因,故在源代码org.mozilla.javascript.Parser里加入了一些输出预处理过程的代码,发布到测试环境。。。之后发现测试环境一直报与新增代码相关的NoSuchField错误。很奇怪,又是开发环境不报错,测试环境报错。怀疑jar导致Parser类冲突了,搜索了下Parser类,发现Rhino(java版本的js解析器)也有一个Parser,而mvnrepository的yuicompressor是依赖了rhino的jar的。删除rhino的jar后,程序正常。(没有仔细阅读yuicompressor的源码,不知此举会不会带来其他一些bug)
jar在不同应用服务器里的加载顺序会不同,开发环境使用jetty,优先加载了yuicompressor的Parser;测试环境使用tomcat,优先加载了rhino的Parser。在使用yuicompressor的JavaScriptCompressor取压缩js时,报错。程序不能预设jar的加载顺序。