如何通过Webpack的Terser保留文件末尾的Thymeleaf专用注释?
保留JS文件末尾Thymeleaf注释的问题及解决办法
背景说明
我们在使用Thymeleaf时,需要保留两种专用注释来兼容Webpack的JS预处理流程:
- 插值注释:用于让Thymeleaf解析变量,同时保证Webpack处理时JS语法有效:
const errorMessage = /*[[#{registration-ldap.error.message}]]*/ ""; - 禁用解析块:当正则表达式等场景与Thymeleaf分隔符冲突时,用成对注释包裹代码,让Thymeleaf跳过解析这段内容:
/*[# th:inline="none"]*/ _PHONE_REGEX = new RegExp("^[+]*[(]?\d{1,4}[)]?[-\s\./\d]*$"); /*[/]*/
为了让Webpack的Terser插件保留这些注释,我们配置了如下Webpack规则:
const path = require("path"); const TerserPlugin = require("terser-webpack-plugin"); let babelConfig = { test: /\.js$/i, exclude: /node_modules/, use: { loader: "babel-loader", options: { presets: ["@babel/preset-env"] }, } }; let config = { entry: { scripts: path.resolve(__dirname, "src/main/resources/static/source/js/scripts-bundle-entry.js") }, output: { filename: "./js/famous-[name].js", path: path.resolve(__dirname, "src/main/resources/static/build") }, mode: "production", watch: true, module: { rules: [babelConfig] }, optimization: { splitChunks: { chunks: "all" }, minimize: true, minimizer: [ new TerserPlugin({ terserOptions: { // 保留以[开头的注释 format: { comments: /^\[/ } } }) ] }, plugins: [] } module.exports = config;
遇到的问题
当上述禁用解析块的代码放在文件末尾时,最后一条结束注释/*[/]*/会被Terser插件删掉,输出结果变成:
/*[# th:inline="none"]*/ _PHONE_REGEX=new RegExp("^[+]*[(]?\d{1,4}[)]?[-\s./\d]*$");
而且不止自定义的Thymeleaf注释,@license这类Terser内置的保留注释,只要放在文件末尾也会被删除。
解决办法
方法1:优化注释匹配规则+手动添加末尾占位符
Terser对文件末尾的孤立注释存在处理逻辑问题,我们可以:
- 调整注释匹配规则,确保Thymeleaf的结束注释也被纳入保留范围:
修改Terser的comments配置为:
或者更精准匹配Thymeleaf的注释格式:format: { comments: /^\[|^\[\/\]/ }comments: /^\[#.*\]$|^\[\/\]$/ - 在文件末尾添加一个无意义的空语句
;,让Terser不把最后一条注释判定为"无关联的末尾注释":/*[# th:inline="none"]*/ _PHONE_REGEX = new RegExp("^[+]*[(]?\d{1,4}[)]?[-\s\./\d]*$"); /*[/]*/ ;
方法2:用自定义loader自动添加末尾占位符
不想手动给每个文件加;的话,可以写一个简单的自定义loader,自动给JS文件末尾追加空语句:
- 创建
src/loaders/append-semicolon-loader.js文件:module.exports = function(source) { return source + '\n;'; }; - 在Webpack配置中修改babel规则,添加这个loader:
let babelConfig = { test: /\.js$/i, exclude: /node_modules/, use: [ { loader: "babel-loader", options: { presets: ["@babel/preset-env"] }, }, path.resolve(__dirname, 'src/loaders/append-semicolon-loader.js') ] };
方法3:调整Terser的保留选项(备选)
如果前两种方法无效,可以尝试开启Terser的keep_classnames或keep_fnames选项,强制保留更多代码上下文,避免注释被误删。但这可能会保留额外的未压缩代码,需要根据项目情况权衡:
new TerserPlugin({ terserOptions: { format: { comments: /^\[|^\[\/\]/ }, keep_classnames: true, keep_fnames: true } })
内容的提问来源于stack exchange,提问作者Slevin
相关产品推荐
相关产品推荐

