Đầu ra trình tải tệp Webpack [Module đối tượng]


40

Tôi đang sử dụng webpack với HtmlWebpackPlugin, html-loaderfile-loader. Tôi có một cấu trúc dự án đơn giản trong đó tôi không sử dụng khung, mà chỉ có bản thảo. Vì vậy, tôi viết mã HTML của tôi trực tiếp đến index.html. Tôi cũng sử dụng tệp HTML này làm mẫu của mình HtmlWebpackPlugin.

Vì tất cả các trang web tôi cần phải đặt một hình ảnh đề cập đến một PNG trong thư mục tài sản của tôi. file-loadernên tải đúng tệp đặt tên tệp mới vào trong srcthẻ nhưng đó không phải là điều đang xảy ra. Thay vào đó, như giá trị của srcthẻ, tôi có [object Module]. Tôi giả sử file-loaderphát ra một số đối tượng và nó được biểu diễn như thế này khi .toString()phương thức của nó được chạy. Tuy nhiên, tôi có thể thấy rằng file-loaderđã xử lý tệp thành công và được phát ra với tên mới cho đường dẫn đầu ra. Tôi không nhận được lỗi. Đây là cấu hình webpack của tôi và 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>

Cơ cấu dự án:

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

Chỉnh sửa gói phụ thuộc của tôi.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"

Câu trả lời:


70

Theo tài liệu trình tải tệp :

Theo mặc định, trình tải tệp tạo các mô-đun JS sử dụng cú pháp mô-đun ES. Có một số trường hợp sử dụng các mô-đun ES là có lợi, như trong trường hợp ghép mô-đun và rung cây.

Dường như webpack giải quyết require()các cuộc gọi mô-đun ES đến một đối tượng trông như thế này : {default: module}, thay vì chính mô-đun làm phẳng. Hành vi này có phần gây tranh cãi và được thảo luận trong vấn đề này .

Do đó, để có được srcthuộc tính của bạn để giải quyết chính xác, bạn cần có khả năng truy cập vào thuộc defaulttính của mô-đun xuất. Nếu bạn đang sử dụng một khung công tác, bạn sẽ có thể làm một cái gì đó như thế này:

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

Ngoài ra, bạn có thể kích hoạt cú pháp mô-đun CommonJS của trình tải tệp, gói web nào sẽ phân giải trực tiếp đến chính mô-đun. Đặt esModule:falsetrong cấu hình gói webpack của bạn.

webpack.config.js:

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

Điều đó đã làm việc. Tuy nhiên nó vẫn còn chút ma thuật. Nếu bạn có ý tưởng về lý do tại sao đây là trường hợp, bạn cũng có thể giải thích nó trong câu trả lời của bạn? Cảm ơn.
Bora

@Bora - Đã làm thêm một ít nghiên cứu và cập nhật câu trả lời.
stellr42

cảm ơn, đây chính xác là những gì tôi cần
Matan Tubul

Điều này bit tôi trong một bản cập nhật từ Angular 8đến Angular 9như được mang file-loadertừ phiên bản 4.2.0đến 6.0.0. Sử dụng require(...).defaultcố định nó cho tôi.
ebhh2001

8

Khắc phục đề xuất của @ stellr42 esModule: falsetrong file-loadercấu hình của bạn là cách giải quyết tốt nhất tại thời điểm hiện tại.

Tuy nhiên, đây thực sự là một lỗi html-loaderđang được theo dõi tại đây: https://github.com/webpack-contrib/html-loader/issues/203

Dường như hỗ trợ ES Mô-đun đã được thêm vào file-loader, css-loadervà những người bạn khác, nhưng html-loaderđã bỏ qua.

Khi lỗi này được khắc phục, sẽ tốt hơn để xóa esModule: falsevà chỉ cần nâng cấp html-loader, vì Mô-đun ES cung cấp một số lợi ích nhỏ (như đã đề cập trong tài liệu )

Ngoài ra, nếu (như tôi), bạn thấy vấn đề này vì bạn gặp sự cố khi tải hình ảnh từ CSS (thay vì từ HTML), thì cách khắc phục chỉ là nâng cấp css-loader, không cần phải tắt Mô-đun ES.


2

Điều này xảy ra trên phiên bản trình tải tệp 5.0.2, phiên bản trước hoạt động tốt mà không cần gọi thuộc defaulttính


0

Chỉ cần cập nhật trình tải tệp của tôi lên ^ 5.0.2 phút trước.

Tôi biết esModule: falselà sửa chữa được đề xuất nhưng nó không làm việc cho tôi.

Sửa chữa của tôi <img src={require('assets/logo.png').default}/>là lạ. Lần đầu tiên sử dụng .defaultnhưng nó đã làm việc.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.