【问题标题】:Prevent HtmlWebpackPlugin from minimizing line breaks in production防止 HtmlWebpackPlugin 最小化生产中的换行符
【发布时间】:2021-11-30 15:33:04
【问题描述】:

这是我的 webpack 配置的相关部分:

plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html',
      hash: false, // for testing purposes
      minify: false,
    }),    
  ]

尽管有minify: false,但如果mode: 'production',HTML 会变成一行。如果mode: 'development',那么它是多行。如果我更改hash: true,那么它将变成一行带有用于缓存清除的查询字符串哈希,这证明它读取了这个配置对象。

但为什么它会截断换行符?我尝试specify an object并设置collapseWhitespace和其他道具而不是minify: false,但它也没有效果,仍然是一行。以下是 package.json 的版本列表:

"devDependencies": {
    "@babel/cli": "^7.14.5",
    "@babel/core": "^7.14.6",
    "@babel/preset-env": "^7.14.5",
    "babel-loader": "^8.2.2",
    "babel-plugin-angularjs-annotate": "^0.10.0",
    "css-loader": "^5.2.6",
    "css-minimizer-webpack-plugin": "3.0.1",
    "html-loader": "^2.1.2",
    "html-webpack-plugin": "5.3.1",
    "mini-css-extract-plugin": "1.6.0",
    "postcss": "^8.3.4",
    "style-loader": "^2.0.0",
    "webpack": "5.39.0",
    "webpack-cli": "4.7.2",
    "webpack-dev-server": "3.11.2",
    "webpack-merge": "^5.8.0"
  }

编辑:为了澄清,我指的是 webpack 插入的动态包含之间的换行符的截断,这是对捆绑的 JS 和 CSS 文件的引用。无论是生产版本还是开发版本,所有这些文件都恰好出现在一行中。好像没有办法逐行拆分,好像是人小心插入的一样。

为什么在自己的行中查看每个动态包含很有用?例如,如果您想检查订单。目前唯一的选择是向左/向右滚动并尝试记住屏幕外显示的内容,这比从上到下阅读列表更具认知负荷,所有内容都适合一个屏幕而不滚动。

【问题讨论】:

    标签: webpack html-webpack-plugin webpack-production


    【解决方案1】:

    我看到您正在使用 html-loader。我的猜测是,自从您设置 minify: false 以来,在您的情况下进行缩小的不是 HtmlWebpackPlugin,而是 html-loader

    为了阻止 html-loader 缩小,我们可以这样设置:

    test: /\.html$/,
    use: {
      loader: "html-loader",
      options: {
        minimize: false,
      },
    }
    

    但是,由于您还希望在生成的 .html 文件中分别包含 .js.css 文件,因此我们运行成问题。它们在同一行的原因是它们是由 HtmlWebpackPlugin 注入的,一开始没有任何换行符。据我所知,我们没有可以设置的选项。

    解决方案 1

    步骤 1

    我发现的最佳解决方案是使用 EJS (https://ejs.co/) 而不是纯 html 创建我们的模板文件。这使我们可以将 javascript 直接写入模板,并让我们完全控制包含的注入方式。见this答案。

    首先将您的 html 模板文件重命名为 template.ejs 之类的文件。接下来在结束 </head> 标签之前添加这个:

    for (const tag of htmlWebpackPlugin.tags.headTags) { %>
      <%= tag %><%
    } %>
    

    请确保不要启用自动格式,因为我们依靠此处的换行符来生成正确的输出格式。根据您使用的 HtmlWebpackPlugin 版本,除了 headTags 之外,您还可能使用 bodyTags。在我看来,至少在最新版本中,他们选择将 script 包含在带有 defer 标志的头部以延迟执行,这也是性能最高的据我了解的方式。

    第二步

    接下来,我们需要在 HtmlWebpackPlugin 选项中更改模板的路径,并同时禁用包含的自动注入,如下所示:

    new HtmlWebpackPlugin({
      template: "./src/template.ejs",
      inject: false
    }),
    

    第三步

    由于 HtmlWebpackPlugin 有一个内置的备用 .ejs 解析器,我们不需要为此安装任何额外的加载器。唯一的问题是,由于您使用的是 html-loader,我假设您的模板文件中有资产,例如图像等。如果您要创建一个新规则来测试 .ejs 文件并使用 html-loader 来处理它们确实可以将硬编码的 src 包含替换为动态的包含,因为这是加载器的目的。但是,为 .ejs 文件指定一个加载器会阻止 HtmlWebpackPlugin 使用它的后备解析器,因此所有模板变量(&lt;% %&gt; 中的那些)都不会被解析。

    然而我们实际上根本不需要 html-loader。相反,您可以使用 EJS 在模板文件中要求您的资产,如下所示:

    <img src="<%= require('./assets/myimage.jpg') %>" />
    

    解决方案 2

    如果由于某种原因您需要/更喜欢使用 html-loader,则可以使用另一种方法来解决此问题。

    由于 HtmlWebpackPluginhtml-loader 被激活时不会使用它的后备 EJS 解析器,我们需要使用另一个加载器来解析它,称为 ejs-loader。不过有一个小问题:当 html-loader 解析模板文件时,它会生成 javascript。由于 ejs-loader 不希望收到 javascript,因此我们需要先将其转换回 EJS 格式。这可以通过另一个名为 extract-loader 的加载器来完成。

    解决方案 1 中的 步骤 1 开始。接下来我们需要安装两个新的加载器:

    yarn add -D ejs-loader extract-loader
    

    之后,我们将它们添加到 webpack 配置 中的模块规则。确保也为 html-loaderesModule 设置为 false,因为 extract-loader 无法处理:

    module: {
    rules: [
      {
        test: /\.ejs$/,
        use: [
        {
          loader: "ejs-loader",
          options: {
            esModule: false
          }
          },
          'extract-loader',
          {
          loader: "html-loader",
          options: {
            esModule: false
          },
        }]
      },
    
      ...
    

    此设置从 html-loader 开始,它会自动解析任何 src 包含并将其转换为 require 语句。它生成 javascript 代码,extract-loader 将其转换回 EJS。最后 ejs-loader 解析 模板变量,在这种情况下 js / css 的列表包括。 p>

    【讨论】:

    • 这是一个很好的答案,但它并没有解决我的问题,因为所有动态 JS/CSS 包含仍然在一行中。其余的都像原版一样分成多行,所以我会投赞成票。但我不能接受,因为它并不能完全解决问题。也可以通过将 webpack 切换到开发模式来实现相同的行为。
    • @Neolisk 我已经更新了解决 .js 文件的答案。
    • 我不是这个意思。默认情况下,开发设置不会缩小 JS。但它仍然将所有 JS 和 CSS 导入放在一行 in HTML.
    • @Neolisk 好吧,我误会了。我现在已经用解决该问题的方法更新了答案。我认为您还应该编辑您的原始问题,因为目前尚不清楚您是否也在寻找一种方法来控制 js/css 的注入。
    • 我需要 html-loader 来处理分散在应用程序中的 AngularJS 模板,有数百个。 Webpack 需要用内容散列版本替换所有提及的静态资源。它不仅仅是一个 html 文件。将跨越 50k LOC 的数百个 html 转换为 ejs 是不可行的。我现在意识到将所有动态包含作为输出 html 中的一行是一个相对较小的问题。尤其是考虑到您上面概述的努力和权衡。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-06-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多