【问题标题】:Webpack file-loader outputs [object Module]Webpack 文件加载器输出 [object Module]
【发布时间】:2020-03-23 00:15:09
【问题描述】:

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

与所有网站一样,我需要在我的资产文件夹中放置一个引用 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
    })
  ]
};

index.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"

【问题讨论】:

    标签: javascript html webpack


    【解决方案1】:

    根据文件加载器docs:

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

    似乎 webpack 将 ES 模块 require() 调用解析为如下所示的对象:{default: module},而不是扁平化模块本身。这种行为有些争议,在this issue 中进行了讨论。

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

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

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

    webpack.config.js:

     {
            test: /\.(png|jpe?g|gif)$/i,
            use: [
              {
                loader: 'file-loader',
                options: {
                  esModule: false,
                },
              },
            ],
          },
    

    【讨论】:

    • 那行得通。然而,它仍然有点神奇。如果您对为什么会这样有想法,您是否也可以在答案中解释它?谢谢。
    • @Bora -- 做了更多研究并更新了答案。
    • 在从 Angular 8 更新到 Angular 9 的过程中,这让我有点吃惊,因为这将 file-loader 从版本 4.2.0 带到了 6.0.0。使用require(...).default 为我修复了它。
    • 我在升级文件加载器后遇到了这个问题。仔细查看更新日志,我发现 esModule 的默认值在 5.0.0 版本中更改为 true。
    • 使用 react 16.13.1 我遇到了同样的问题,即 require 不起作用使用 require(...).default 为我修复了它
    【解决方案2】:

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

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

    file-loadercss-loader等朋友好像增加了对ES Module的支持,但是漏掉了html-loader

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

    或者,如果(像我一样),您发现这个问题是因为您在 从 CSS(而不是从 HTML)加载图像时遇到问题,那么解决方法就是升级 css-loader,无需禁用 ES 模块。

    【讨论】:

      【解决方案3】:

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

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

      我的解决方法是 &lt;img src={require('assets/logo.png').default}/&gt;,这很奇怪。第一次使用.default,但是成功了。

      【讨论】:

        【解决方案4】:

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

        【讨论】:

          【解决方案5】:

          而不是这个:&lt;img src="require('assets/logo.png').default"/&gt;

          像这样使用它:&lt;img src={require('assets/logo.png').default}/&gt;

          【讨论】:

            【解决方案6】:

            我在 vuejs 中遇到了同样的问题,esModule:false 对我不起作用。 相反,我使用了@kerubim 解决方案并修复了它,但仅在生产模式和开发模式下我会遇到一些错误。

            所以我在util.js 中写了这个函数,解决了我的问题。

            maybeDefault: (module) => {
            
              if (typeof module === "object") {
            
                module = module.default;
              }
            
              return module;
            },
            

            使用示例:

            let logo = 'logo.svg';
            util.maybeDefault(require(`img/svg/logos/${logo}`));
            

            【讨论】:

            • @Dharman 抱歉,我认为这很清楚,所以是的。我使用了这个功能并解决了我的问题。但在vuejs,当然也可以用于其他用途。
            • 这在 Gatsby 中为我工作,无需重写 webpack 配置
            【解决方案7】:

            在 react js 中使用 "default" 后跟 require 来显示动态图像

            src={require('../images/'+image_name+'.png').default}

            【讨论】:

              【解决方案8】:

              对于Next.JS

              // require(...).default.src
              <img src={require("../public/images/avatar.png").default.src} width={256} height={256} />
              
              

              【讨论】:

                【解决方案9】:

                这是一个奇怪的问题,仍然不确定我的问题是如何解决的。

                所以我删除了我的node_modulepackage-lock.json 并运行npm install --force

                之后效果很好

                【讨论】:

                  猜你喜欢
                  • 2017-07-04
                  • 2017-10-02
                  • 2017-03-20
                  • 2019-12-20
                  • 1970-01-01
                  • 2020-03-26
                  • 2017-02-27
                  • 2023-01-20
                  • 2019-12-31
                  相关资源
                  最近更新 更多