DEBUG.WIKI
V.PS:让项目靠近用户,亚太、欧洲、北美 KVM VPS
IPPeak:从目标地区访问网页,住宅代理、SEO 监测、广告验证
ZgoCloud:多地区部署,按需选节点;日本、美国、香港、德国

webpack 生产构建损坏服务端模板,关闭这类资产的 HTML 压缩

webpack 的内置 HTML 压缩会把尚未展开的服务端模板当成 HTML 处理。关闭对应压缩或为复制规则设置跳过标记,再用模板引擎验收完整结果。

把服务端模板交给 copy-webpack-plugin 原样复制,开发环境正常,升级 webpack 后生产模板却少了 %},应检查新增的 HTML 压缩步骤。复制插件保持输入不变,不代表后面的资产优化也保持它不变。

具体组合涉及 webpack 5.110.0 引入的内置 HTML 压缩;原报告在 5.110.0 至 5.110.3 核到相同损坏,使用 copy-webpack-plugin 14.0.0、webpack-cli 7.2.3 与 Node 24.19.0。输入类似:

<input type="text"{% if required %} required{% endif %}>
<div class="btn{% if active %} btn-active{% endif %}"></div>

这不是已经展开的标准 HTML。压缩器可能把模板中的 %} 当作属性名或 class token,并按 HTML 规则去重;模板结束符随之缺失。普通 HTML 中移除可省略的属性引号并非这里的问题,关键是模板语法被当成 HTML 数据处理。

最直接的做法是让这些模板避开内置 HTML 压缩。只希望停用这一类压缩时,可在相应版本支持的配置中使用:

module.exports = {
  mode: 'production',
  optimization: {
    minimize: { html: false },
  },
};

这个对象写法针对新增的按资产类型配置契约,仍保留 JavaScript 与 CSS 的压缩。已核 5.111.1 也支持对应的 minimizeOptions: { html: false } 选项。合并配置时选择一种清晰写法,不要用停止所有生产优化掩盖单类模板问题。

若普通页面仍需压缩,而只有一组复制的服务端模板要保持字节,可在复制规则中标记它们不再参与后续压缩:

const CopyPlugin = require('copy-webpack-plugin');
module.exports = {
  plugins: [
    new CopyPlugin({
      patterns: [{
        from: 'templates',
        to: 'templates',
        info: { minimized: true },
      }],
    }),
  ],
};

minimized: true 是给资产处理链的跳过标记,不表示模板已被某个工具正确压缩。这种精确规则适合同时保留普通 HTML 优化;应确认输出目录与原项目结构匹配,不要把所有资产都标记成已优化。

重新执行生产构建,逐字比较受影响模板输入与输出,尤其是条件属性、class 中的条件段以及空白位置不同的对照。然后通过真实服务端模板引擎编译并渲染条件为真、为假的两种结果。仅浏览器能打开某个静态 HTML,不能验收尚未经过服务端解释的语法。

内置压缩器后续修补过部分序列化行为,但不能由此保证 Django、Jinja、Twig 等任意模板语法都成为受支持 HTML。需要压缩最终页面时,更稳妥的处理顺序是先由模板引擎完成展开,再让适合该输出的工具处理合法 HTML。若模板仍被改写,查看是否另有 loader、插件或发布步骤参与,避免只关闭一个阶段便停止排查。