Выходные данные загрузчика файлов Webpack [объектный модуль]


40

Я использую веб-пакет с HtmlWebpackPlugin, html-loaderи file-loader. У меня есть простая структура проекта, в которой я использую не фреймворки, а только машинопись. Таким образом, я пишу свой HTML-код непосредственно в index.html. Я также использую этот HTML-файл в качестве шаблона в HtmlWebpackPlugin.

Как и все веб-сайты, мне нужно поместить изображение, которое ссылается на 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"

Ответы:


70

Согласно документации по загрузчику файлов :

По умолчанию загрузчик файлов генерирует модули JS, которые используют синтаксис модулей ES. В некоторых случаях использование модулей ES полезно, например, в случае объединения модулей и встряхивания дерева.

Кажется, что веб-пакет разрешает require()вызовы модуля ES объекту, который выглядит следующим образом: {default: module}вместо самого сплющенного модуля. Такое поведение является несколько спорным и обсуждается в этом вопросе .

Следовательно, для srcправильного разрешения вашего атрибута вам необходимо иметь доступ к defaultсвойству экспортируемого модуля. Если вы используете фреймворк, вы сможете сделать что-то вроде этого:

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

Кроме того, вы можете включить синтаксис модуля CommonJS для загрузчика файлов, который веб-пакет разрешит непосредственно для самого модуля. Установите esModule:falseв своем конфиге webpack.

webpack.config.js:

 {
        test: /\.(png|jpe?g|gif)$/i,
        use: [
          {
            loader: 'file-loader',
            options: {
              esModule: false,
            },
          },
        ],
      },

Это сработало. Однако это все еще немного волшебства. Если у вас есть идеи о том, почему это так, не могли бы вы также объяснить это в своем ответе? Спасибо.
Бора

@ Бора - сделал немного больше исследований и обновил ответ.
stellr42

спасибо, это именно то, что мне нужно
Матан Тубул

Это меня укусило во время обновления от Angular 8до Angular 9как file-loaderот версии 4.2.0до 6.0.0. Используя require(...).defaultисправил это для меня.
ebhh2001

8

Рекомендуемое исправление @ stellr42 esModule: falseв вашей file-loaderконфигурации - лучший обходной путь в настоящее время.

Тем не менее, это на самом деле ошибка, html-loaderкоторая отслеживается здесь: https://github.com/webpack-contrib/html-loader/issues/203

Похоже , поддержка ES Модуль была добавлена file-loader, css-loaderи другими друзья, но html-loaderбыла упущена.

Как только эта ошибка будет исправлена, будет лучше удалить esModule: falseи просто обновить ее html-loader, так как модули ES предлагают некоторые незначительные преимущества (как упомянуто в документации )

В качестве альтернативы, если (как и я) вы обнаружили эту проблему, потому что у вас были проблемы с загрузкой изображения из CSS (а не из HTML), тогда исправление - просто обновить css-loader, не нужно отключать модули ES.


2

Это происходит в файловом загрузчике версии 5.0.2, более ранняя версия работает нормально без вызова defaultсвойства


0

Только что обновил мой загрузчик файлов до ^ 5.0.2 минут назад.

Я знаю, esModule: falseбыло предложено исправить, но это не сработало для меня.

Мое исправление <img src={require('assets/logo.png').default}/>было странным. Первый раз, .defaultно он работал.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.