Виводить завантажувач файлів Webpack [модуль об'єкта]


40

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

Оскільки всі веб-сайти мені потрібно помістити зображення, яке посилається на PNG, у папку моїх активів. file-loaderслід завантажити файл правильно, помістивши нове ім’я файлу всередині srcтегу, але це не те, що відбувається. Натомість як значення srcтега у мене є [object Module]. Я припускаю, що file-loaderвипускає якийсь об'єкт, і він представлений так, коли його .toString()метод запускається. Однак я можу бачити, що file-loaderфайл обробив успішно і видав нове ім'я до вихідного шляху. Я не отримую помилок. Ось моя конфігурація вебпакету та 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 вигідно, як, наприклад, у випадку конкатенації модулів та струшування дерев.

Здається, що webpack вирішує require()виклики модуля ES до об'єкта, який виглядає приблизно так: {default: module}замість самого сплющеного модуля. Така поведінка дещо суперечлива і обговорюється в цьому питанні .

Тому, щоб ваш srcатрибут правильно розв’язувався, вам потрібно мати доступ до defaultвластивості експортованого модуля. Якщо ви використовуєте рамку, ви повинні мати можливість зробити щось подібне:

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

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

webpack.config.js:

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

Це спрацювало. Однак це все-таки трошки магія. Якщо у вас є ідеї, чому це так, чи можете ви також пояснити це у своїй відповіді? Дякую.
Бора

@Bora - зробив трохи більше досліджень та оновлену відповідь.
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/isissue/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.