Sorties du chargeur de fichiers Webpack [Module objet]

40

J'utilise webpack avec HtmlWebpackPlugin, html-loaderet file-loader. J'ai une structure de projet simple dans laquelle je n'utilise pas de frameworks, mais uniquement du texte dactylographié. Ainsi, j'écris directement mon code HTML index.html. J'utilise également ce fichier HTML comme modèle dans HtmlWebpackPlugin.

Comme tous les sites Web, j'ai besoin de mettre une image qui fait référence à un PNG dans mon dossier d'actifs. file-loaderdevrait charger le fichier correctement mettre le nouveau nom de fichier dans la srcbalise mais ce n'est pas ce qui se passe. Au lieu de cela, comme la valeur de la srcbalise, je l'ai [object Module]. Je suppose que le file-loaderémet un objet et il est représenté comme ceci lorsque sa .toString()méthode est exécutée. Cependant, je peux voir que file-loaderle fichier a été traité avec succès et émis avec un nouveau nom dans le chemin de sortie. Je ne reçois aucune erreur. Voici ma configuration webpack et 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>

Structure du projet:

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

Modifiez mes dépendances 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
la source

Réponses:

70

Selon les documents du chargeur de fichiers :

Par défaut, le chargeur de fichiers génère des modules JS qui utilisent la syntaxe des modules ES. Dans certains cas, l'utilisation de modules ES est bénéfique, comme dans le cas de la concaténation de modules et du tremblement d'arbre.

Il semble que webpack résout les require()appels du module ES à un objet qui ressemble à ceci :, {default: module}au lieu du module aplati lui-même. Ce comportement est quelque peu controversé et est abordé dans ce numéro .

Par conséquent, pour obtenir la srcrésolution correcte de votre attribut, vous devez pouvoir accéder à la defaultpropriété du module exporté. Si vous utilisez un framework, vous devriez pouvoir faire quelque chose comme ceci:

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

Alternativement, vous pouvez activer la syntaxe du module CommonJS du chargeur de fichiers, que le webpack résoudra directement au module lui-même. Définissez esModule:falsedans votre configuration webpack.

webpack.config.js:

 {
        test: /\.(png|jpe?g|gif)$/i,
        use: [
          {
            loader: 'file-loader',
            options: {
              esModule: false,
            },
          },
        ],
      },
stellr42
la source
Ça a marché. Mais c'est encore un peu magique. Si vous avez des idées sur la raison pour laquelle c'est le cas, pourriez-vous également l'expliquer dans votre réponse? Merci.
Bora
@Bora - A fait un peu plus de recherche et mis à jour la réponse.
stellr42
merci, c'est exactement ce dont j'ai besoin
Matan Tubul
Cela m'a mordu lors d'une mise à jour de Angular 8à Angular 9comme celle apportée file-loaderde la version 4.2.0à 6.0.0. L'utiliser l'a require(...).defaultcorrigé pour moi.
ebhh2001
8

La correction suggérée de @ stellr42 esModule: falsedans votre file-loaderconfiguration est la meilleure solution de contournement à l'heure actuelle.

Cependant, il s'agit en fait d'un bogue dans html-loaderlequel est suivi ici: https://github.com/webpack-contrib/html-loader/issues/203

Il ressemble à un soutien ES module a été ajouté à file-loader, css-loaderet d' autres amis, mais html-loadera manqué.

Une fois ce bug corrigé, il sera préférable de le supprimer esModule: falseet de simplement le mettre à niveau html-loader, car les modules ES offrent quelques avantages mineurs (comme mentionné dans la documentation )

Alternativement, si (comme moi), vous avez trouvé ce problème parce que vous rencontriez des problèmes pour charger une image à partir de CSS (au lieu de HTML), le correctif consiste simplement à mettre à niveau css-loader, pas besoin de désactiver les modules ES.

brindyblitz
la source
2

Cela se produit sur le chargeur de fichiers version 5.0.2, la version antérieure fonctionne correctement sans appeler la defaultpropriété

Jora
la source
0

Je viens de mettre à jour mon chargeur de fichiers en ^ 5.0.2 minutes.

Je sais que esModule: falsec'était le correctif suggéré mais cela n'a pas fonctionné pour moi.

Ma solution était <img src={require('assets/logo.png').default}/>ce qui était bizarre. Première utilisation .defaultmais cela a fonctionné.

Kerubim
la source