Wyjścia modułu ładującego pliki Webpack [moduł obiektu]

40

Używam webpack z HtmlWebpackPlugin, html-loaderi file-loader. Mam prostą strukturę projektu, w której nie używam ram, a jedynie maszynopis. Dlatego piszę mój kod HTML bezpośrednio na index.html. Używam również tego pliku HTML jako mojego szablonu HtmlWebpackPlugin.

Jak wszystkie strony internetowe, muszę umieścić obraz, który odnosi się do PNG w moim folderze zasobów. file-loaderpowinien poprawnie załadować plik, umieść nową nazwę pliku w srctagu, ale tak się nie dzieje. Zamiast tego srcmam wartość tagu [object Module]. Zakładam, że file-loaderemituje jakiś obiekt i jest on reprezentowany w ten .toString()sposób po uruchomieniu jego metody. Widzę jednak, że file-loaderplik został przetworzony pomyślnie i został wysłany z nową nazwą do ścieżki wyjściowej. Nie dostaję błędów. Oto moja konfiguracja pakietu internetowego i 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>

Struktura projektu:

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

Edytuj zależności My 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
źródło

Odpowiedzi:

70

Według dokumentów modułu ładującego pliki :

Domyślnie moduł ładujący pliki generuje moduły JS korzystające ze składni modułów ES. W niektórych przypadkach korzystanie z modułów ES jest korzystne, na przykład w przypadku łączenia modułów i wstrząsania drzewem.

Wygląda na to, że webpack rozwiązuje require()wywołania modułu ES do obiektu wyglądającego tak: {default: module}zamiast do samego spłaszczonego modułu. To zachowanie jest nieco kontrowersyjne i zostało omówione w tym numerze .

Dlatego, aby srcpoprawnie rozwiązać atrybut, musisz mieć dostęp do defaultwłaściwości wyeksportowanego modułu. Jeśli używasz frameworka, powinieneś być w stanie zrobić coś takiego:

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

Alternatywnie możesz włączyć składnię modułu CommonJS modułu ładującego pliki, który webpack rozpozna bezpośrednio w samym module. Ustaw esModule:falsew konfiguracji pakietu internetowego.

webpack.config.js:

 {
        test: /\.(png|jpe?g|gif)$/i,
        use: [
          {
            loader: 'file-loader',
            options: {
              esModule: false,
            },
          },
        ],
      },
stellr42
źródło
To się udało. Jednak wciąż jest trochę magiczna. Jeśli masz pomysły, dlaczego tak jest, czy możesz to również wyjaśnić w swojej odpowiedzi? Dzięki.
Bora
@Bora - Zrobiłem trochę więcej badań i zaktualizowałem odpowiedź.
stellr42,
dzięki, właśnie tego potrzebuję
Matan Tubul
To mnie ugryzło podczas aktualizacji z Angular 8 do, Angular 9ponieważ przeniesiono ją file-loaderz wersji 4.2.0do 6.0.0. Za pomocą require(...).defaultnaprawiłem to dla mnie.
ebhh2001
8

Sugerowana poprawka @ stellr42 esModule: falsew twojej file-loaderkonfiguracji jest najlepszym obejściem w tej chwili.

Jest to jednak błąd, w html-loaderktórym śledzi się tutaj: https://github.com/webpack-contrib/html-loader/issues/203

Wygląda to jak wsparcie ES moduł został dodany do file-loader, css-loaderi innych przyjaciół, ale html-loaderzostała pominięta.

Po usunięciu tego błędu lepiej będzie go usunąć esModule: falsei po prostu zaktualizować html-loader, ponieważ moduły ES oferują kilka drobnych korzyści (jak wspomniano w dokumentacji )

Alternatywnie, jeśli (tak jak ja) znalazłeś ten problem, ponieważ miałeś problemy z ładowaniem obrazu z CSS (zamiast z HTML), wtedy poprawką jest tylko aktualizacja css-loader, nie trzeba wyłączać modułów ES.

brindyblitz
źródło
2

Dzieje się tak w programie ładującym pliki w wersji 5.0.2, wcześniejsza wersja działa dobrze bez wywoływania default właściwości

Jora
źródło
0

Właśnie zaktualizowałem mój moduł ładujący pliki do ^ 5.0.2 minut temu.

wiem esModule: false to sugerowana poprawka, ale to nie działało dla mnie.

Moja poprawka <img src={require('assets/logo.png').default}/>była dziwna. Pierwszy raz używałem, .defaultale zadziałało.

kerubim
źródło