Webpack 文件加载器输出 [object Module]

Posted

技术标签:

【中文标题】Webpack 文件加载器输出 [object Module]【英文标题】:Webpack file-loader outputs [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"

【问题讨论】:

【参考方案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

之后效果很好

【讨论】:

以上是关于Webpack 文件加载器输出 [object Module]的主要内容,如果未能解决你的问题,请参考以下文章

webpack 文件加载器重复文件

Webpack入门指南: 入口,输出,加载器和插件

Webpack 样式加载器未将样式注入 DOM

Babel Webpack 错误:您可能需要适当的加载器来处理此文件类型

尝试使用文件加载器和 webpack 加载大型 json 文件

Webpack:无法解析模块“文件加载器”