Salidas del cargador de archivos Webpack [módulo de objeto]

40

Estoy usando webpack con HtmlWebpackPlugin, html-loadery file-loader. Tengo una estructura de proyecto simple en la que no uso marcos, sino solo mecanografiado. Por lo tanto, escribo mi código HTML directamente en index.html. También uso este archivo HTML como mi plantilla HtmlWebpackPlugin.

Como todos los sitios web, necesito poner una imagen que haga referencia a PNG en mi carpeta de activos. file-loaderdebe cargar el archivo correctamente, poner el nuevo nombre de archivo dentro de la srcetiqueta, pero eso no es lo que está sucediendo. En cambio, como el valor de la srcetiqueta, tengo [object Module]. Supongo que file-loaderemite algún objeto y se representa así cuando .toString()se ejecuta su método. Sin embargo, puedo ver que file-loaderha procesado el archivo con éxito y emitió un nuevo nombre a la ruta de salida. No consigo errores. Aquí está mi configuración de paquete web y 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>

Estructura del proyecto:

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

Editar mis dependencias 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"
Bora
fuente

Respuestas:

70

Según los documentos del cargador de archivos :

De manera predeterminada, el cargador de archivos genera módulos JS que utilizan la sintaxis de los módulos ES. Hay algunos casos en los que el uso de módulos ES es beneficioso, como en el caso de la concatenación de módulos y el movimiento de los árboles.

Parece que webpack resuelve las require()llamadas del módulo ES a un objeto que se ve así: en {default: module}lugar del módulo aplanado en sí. Este comportamiento es algo controvertido y se discute en este número .

Por lo tanto, para que su srcatributo se resuelva correctamente, debe poder acceder a la defaultpropiedad del módulo exportado. Si está utilizando un marco, debería poder hacer algo como esto:

<img src="require('assets/logo.png').default"/>

Alternativamente, puede habilitar la sintaxis del módulo CommonJS del cargador de archivos, que webpack resolverá directamente en el propio módulo. Establecer esModule:falseen la configuración de su paquete web.

webpack.config.js:

 {
        test: /\.(png|jpe?g|gif)$/i,
        use: [
          {
            loader: 'file-loader',
            options: {
              esModule: false,
            },
          },
        ],
      },
stellr42
fuente
Eso funciono. Sin embargo, todavía es un poco mágico. Si tiene ideas sobre por qué este es el caso, ¿podría explicarlo también en su respuesta? Gracias.
Bora
@Bora - Hice un poco más de investigación y la respuesta actualizada.
stellr42
gracias, esto es exactamente lo que necesito
Matan Tubul
Esto me mordió durante una actualización de Angular 8a Angular 9como eso trajofile-loader de la versión 4.2.0a 6.0.0. El uso lo require(...).defaultarregló para mí.
ebhh2001
8

La solución sugerida de @ stellr42 esModule: falseen su file-loaderconfiguración es la mejor solución en este momento.

Sin embargo, esto es realmente un error en el html-loaderque se está rastreando aquí: https://github.com/webpack-contrib/html-loader/issues/203

Parece que el apoyo ES módulo se añadió a file-loader, css-loadery otros amigos, pero html-loaderse perdió.

Una vez que se solucione este error, será mejor eliminarlo esModule: falsey simplemente actualizarlo html-loader, ya que los módulos ES ofrecen algunos beneficios menores (como se menciona en los documentos )

Alternativamente, si (como yo), encontró este problema porque tenía problemas para cargar una imagen desde CSS (en lugar de desde HTML), entonces la solución es solo actualizar css-loader, no es necesario deshabilitar los módulos ES.

brindyblitz
fuente
2

Esto sucede en el cargador de archivos versión 5.0.2, la versión anterior funciona bien sin llamar a la defaultpropiedad

Jora
fuente
0

Acabo de actualizar mi cargador de archivos a ^ 5.0.2 minutos atrás.

Lo sé esModule: false fue la solución sugerida, pero eso no funcionó para mí.

Mi solución fue <img src={require('assets/logo.png').default}/>que era raro. Primera vez usando .defaultpero funcionó.

Kerubim
fuente