Webpack File-Loader-Ausgaben [Objektmodul]

40

Ich verwende webpack mit HtmlWebpackPlugin, html-loaderund file-loader. Ich habe eine einfache Projektstruktur, in der ich keine Frameworks verwende, sondern nur Typoskript. Daher schreibe ich meinen HTML-Code direkt in index.html. Ich verwende diese HTML-Datei auch als Vorlage in HtmlWebpackPlugin.

Wie bei allen Websites muss ich ein Bild, das auf ein PNG verweist, in meinen Assets-Ordner einfügen. file-loadersollte die Datei korrekt geladen werden, setzen Sie den neuen Dateinamen in das srcTag, aber das ist nicht das, was passiert. Stattdessen habe srcich als Wert des Tags [object Module]. Ich gehe davon aus, dass das file-loaderObjekt emittiert und es so dargestellt wird, wenn seine .toString()Methode ausgeführt wird. Ich kann jedoch sehen, dass file-loaderdie Datei erfolgreich verarbeitet und mit einem neuen Namen an den Ausgabepfad ausgegeben wurde. Ich bekomme keine Fehler. Hier ist meine Webpack-Konfiguration und 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>

Projektstruktur:

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

Bearbeiten Sie meine package.json-Abhängigkeiten:

"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
quelle

Antworten:

70

Gemäß den File-Loader- Dokumenten :

Standardmäßig generiert File-Loader JS-Module, die die Syntax der ES-Module verwenden. In einigen Fällen ist die Verwendung von ES-Modulen von Vorteil, z. B. bei der Verkettung von Modulen und beim Schütteln von Bäumen.

Es scheint, dass Webpack ES-Modulaufrufe require()in ein Objekt auflöst , das wie folgt aussieht: {default: module}anstelle des abgeflachten Moduls selbst. Dieses Verhalten ist etwas umstritten und wird in dieser Ausgabe behandelt .

Damit Ihr srcAttribut korrekt aufgelöst werden kann, müssen Sie daher auf die defaultEigenschaft des exportierten Moduls zugreifen können . Wenn Sie ein Framework verwenden, sollten Sie in der Lage sein, Folgendes zu tun:

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

Alternativ können Sie die CommonJS-Modulsyntax des File-Loaders aktivieren, die das Webpack direkt in das Modul selbst auflöst. esModule:falseStellen Sie in Ihrer Webpack-Konfiguration ein.

webpack.config.js:

 {
        test: /\.(png|jpe?g|gif)$/i,
        use: [
          {
            loader: 'file-loader',
            options: {
              esModule: false,
            },
          },
        ],
      },
stellr42
quelle
Das hat funktioniert. Es ist jedoch immer noch ein bisschen magisch. Wenn Sie Ideen haben, warum dies der Fall ist, können Sie dies auch in Ihrer Antwort erklären? Vielen Dank.
Bora
@Bora - Habe ein bisschen mehr recherchiert und die Antwort aktualisiert.
stellr42
Danke, genau das brauche ich
Matan Tubul
Dies hat mich während eines Updates von Angular 8bis gebissen , Angular 9als das file-loadervon Version 4.2.0zu Version gebracht wurde 6.0.0. Verwenden Sie require(...).defaultes für mich behoben.
ebhh2001
8

Die von @ stellr42 vorgeschlagene Korrektur esModule: falsein Ihrer file-loaderKonfiguration ist derzeit die beste Problemumgehung .

Dies ist jedoch tatsächlich ein Fehler, html-loaderder hier verfolgt wird: https://github.com/webpack-contrib/html-loader/issues/203

Es sieht so aus, als ob die Unterstützung des ES-Moduls und anderer Freunde hinzugefügt file-loaderwurde css-loader, aber html-loadervermisst wurde.

Sobald dieser Fehler behoben ist, ist es besser, ihn zu entfernen esModule: falseund einfach zu aktualisieren html-loader, da ES-Module einige geringfügige Vorteile bieten (wie in den Dokumenten erwähnt ).

Wenn Sie (wie ich) dieses Problem festgestellt haben, weil Sie Probleme beim Laden eines Bilds aus CSS (anstelle von HTML) hatten, besteht die Lösung lediglich in einem Upgrade css-loader, ohne dass ES-Module deaktiviert werden müssen.

brindyblitz
quelle
2

Dies geschieht in File-Loader Version 5.0.2, frühere Version funktioniert einwandfrei, ohne defaultEigenschaft aufzurufen

Jora
quelle
0

Ich habe gerade meinen File-Loader auf ^ 5.0.2 Minuten aktualisiert.

Ich kenne esModule: false war die vorgeschlagene Lösung, aber das hat bei mir nicht funktioniert.

Mein Fix war <img src={require('assets/logo.png').default}/>was komisch war. Zum ersten Mal benutzt, .defaultaber es hat funktioniert.

Kerubim
quelle