Webpack 文件加载器输出 [目标module]

IT技术 javascript html webpack
2021-03-10 11:33:30

我将 webpack 与HtmlWebpackPlugin,html-loaderfile-loader. 我有一个简单的项目结构,其中我不使用框架,而只使用typescript。因此,我将我的 HTML 代码直接写入index.html. 我也使用这个 HTML 文件作为我的模板HtmlWebpackPlugin

与所有网站一样,我需要在我的资产文件夹中放置一个引用 PNG 的图像。file-loader应该正确加载文件,将新文件名放入src标签中,但这不是正在发生的事情。相反,作为src标签的值,我有[object Module]. 我假设它file-loader发出一些对象,并且在.toString()运行它的方法时它是这样表示的但是,我可以看到file-loader已成功处理文件并以新名称发送到输出路径。我没有错误。这是我的 webpack 配置和index.html.

const projectRoot = path.resolve(__dirname, '..');

{
  entry: path.resolve(projectRoot, 'src', 'app.ts'),
  mode: 'production',
  output: {
    path: path.resolve(projectRoot, 'dist'),
    filename: 'app.bundle.js'
  },
  resolve: {
    extensions: ['.ts', '.js']
  },
  module: {
    rules: [
      {
        test: /\.html$/i,
        use: 'html-loader'
      },
      {
        test: /\.(eot|ttf|woff|woff2|svg|png)$/i,
        use: 'file-loader'
      },
      {
        test: /\.scss$/i,
        use: [
          {
            loader: MiniCssExtractPlugin.loader,
            options: {
              hmr: false
            }
          },
          {
            loader: 'css-loader',
            options: {
              sourceMap: false
            }
          },
          {
            loader: 'sass-loader',
            options: {
              sourceMap: false
            }
          }
        ]
      },
      {
        exclude: /node_modules/,
        test: /\.ts$/,
        use: 'ts-loader'
      }
    ]
  },
  plugins: [
    new CleanWebpackPlugin(),
    new HtmlWebpackPlugin({
      template: path.resolve(projectRoot, 'src', 'index.html')
    }),
    new MiniCssExtractPlugin({
      filename: '[name].[hash].css',
      chunkFilename: '[id].[hash].css',
      ignoreOrder: false
    })
  ]
};

索引.html:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title></title>
  </head>
  <body class="dark">
    <header>
      <nav class="navigation">
        <div class="left">
          <img src="assets/logo.png" class="logo"> <!-- This logo is output as [object Module] -->
        </div>
        <div class="right">

        </div>
      </nav>
    </header>
  </body>
</html>

项目结构:

config/
    webpack.config.js
dist/
src/
    styles/
    assets/
        logo.png
    index.html
    app.ts

编辑 我的 package.json 依赖项:

"clean-webpack-plugin": "^3.0.0",
"css-loader": "^3.2.0",
"file-loader": "^5.0.2",
"html-webpack-plugin": "^3.2.0",
"mini-css-extract-plugin": "^0.8.0",
"node-sass": "^4.13.0",
"sass-loader": "^8.0.0",
"style-loader": "^1.0.0",
"ts-loader": "^6.2.1",
"typescript": "^3.7.2",
"webpack": "^4.41.2",
"webpack-cli": "^3.3.10",
"webpack-dev-server": "^3.9.0"
6个回答

根据文件加载器文档

默认情况下,file-loader 生成使用 ES module语法的 JS module。在某些情况下,使用 ES module是有益的,例如module串联和摇树的情况。

似乎 webpack 将 ES modulerequire()调用解析为一个如下所示的对象:{default: module},而不是扁平module本身。这种行为有些争议,并在本期讨论

因此,为了让您的src属性正确解析,您需要能够访问default导出module属性。如果您使用的是框架,则应该能够执行以下操作:

<img src={require('assets/logo.png').default}/> <!-- React -->
<!-- OR -->
<img src="require('assets/logo.png').default"/> <!-- Vue -->

或者,您可以启用文件加载器的 CommonJS module语法,webpack 将直接解析为module本身。esModule:false在你的 webpack 配置中设置

webpack.config.js:

 {
        test: /\.(png|jpe?g|gif)$/i,
        use: [
          {
            loader: 'file-loader',
            options: {
              esModule: false,
            },
          },
        ],
      },
那行得通。然而,它仍然有点神奇。如果您对为什么会这样有想法,您是否也可以在答案中解释一下?谢谢。
2021-04-17 11:33:30
@Bora——做了更多的研究和更新的答案。
2021-04-18 11:33:30
在从Angular 8的更新过程中,这让我感到困惑Angular 9因为file-loader从版本4.2.06.0.0. 使用require(...).default为我修复了它。
2021-04-23 11:33:30
我在升级文件加载器后遇到了这个问题。更仔细地查看更改日志,我看到 esModule 的默认值在 5.0.0 版本中更改为 true。
2021-04-23 11:33:30
使用 react 16.13.1 我遇到了同样的问题,其中 require 不起作用使用 require(...).default 为我修复了它
2021-05-07 11:33:30

@stellr42esModule: false在您的file-loader配置中建议的修复方法是目前最好的解决方法。

然而,这实际上是一个在html-loader这里被跟踪的错误https : //github.com/webpack-contrib/html-loader/issues/203

貌似对file-loadercss-loader、 等朋友添加了 ES Module 支持,但是html-loader被漏掉了。

修复此错误后,最好删除esModule: false并简单升级html-loader,因为 ES module提供了一些小好处(如文档中所述

或者,如果(像我一样)发现这个问题是因为从 CSS(而不是从 HTML)加载图像时遇到问题,那么修复只是升级css-loader,无需禁用 ES module。

刚刚将我的文件加载器更新到 ^5.0.2 分钟前。

我知道这esModule: false是建议的修复方法,但这对我不起作用。

我的解决办法是<img src={require('assets/logo.png').default}/>这很奇怪。第一次使用,.default但有效。

这发生在文件加载器版本 5.0.2 上,早期版本无需调用default属性即可正常工作

取而代之的是: <img src="require('assets/logo.png').default"/>

像这样使用它: <img src={require('assets/logo.png').default}/>