เอาต์พุตตัวโหลดไฟล์ Webpack [โมดูลวัตถุ]


40

ฉันใช้ webpack ด้วยHtmlWebpackPlugin, และhtml-loader file-loaderฉันมีโครงสร้างโครงการง่าย ๆ ที่ฉันไม่ใช้เฟรมเวิร์ก แต่เป็นตัวพิมพ์ดีดเท่านั้น ดังนั้นผมเขียนโค้ด HTML index.htmlของฉันโดยตรงกับ ฉันยังใช้ไฟล์ HTML นี้เป็นเทมเพลตของฉันHtmlWebpackPluginด้วย

ในฐานะที่เป็นเว็บไซต์ทั้งหมดฉันจำเป็นต้องใส่ภาพซึ่งอ้างถึง PNG ในโฟลเดอร์เนื้อหาของฉัน file-loaderควรโหลดไฟล์อย่างถูกต้องใส่ชื่อไฟล์ใหม่ภายในsrcแท็ก แต่นั่นไม่ใช่สิ่งที่เกิดขึ้น แต่เป็นค่าของแท็กฉันมีsrc [object Module]ฉันถือว่าfile-loaderปล่อยวัตถุบางอย่างและมันจะแสดงเช่นนี้เมื่อ.toString()วิธีการทำงานของมัน อย่างไรก็ตามฉันเห็นว่าfile-loaderประมวลผลไฟล์สำเร็จแล้วและปล่อยออกมาด้วยชื่อใหม่ไปยังพา ธ เอาต์พุต ฉันไม่มีข้อผิดพลาด index.htmlนี่คือการตั้งค่าของฉันและ webpack

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

แก้ไข My package.json dependencies:

"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 ของตัวโหลดไฟล์ซึ่ง webpack จะแก้ไขโดยตรงไปยังโมดูลเอง ตั้งค่าesModule:falseในเว็บแพคของคุณ

webpack.config.js:

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

ที่ได้ผล อย่างไรก็ตามมันยังคงเป็นเวทมนตร์เล็กน้อย หากคุณมีแนวคิดเกี่ยวกับสาเหตุที่เป็นเช่นนี้คุณสามารถอธิบายได้ในคำตอบของคุณ? ขอบคุณ
Bora

@Bora - ทำวิจัยเพิ่มเติมและคำตอบที่ปรับปรุงเล็กน้อย
stellr42

ขอบคุณนี่คือสิ่งที่ฉันต้องการ
Matan Tubul

นี้กัดฉันในระหว่างการปรับปรุงจาก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 Module file-loader , css-loaderและเพื่อนคนอื่น ๆ แต่html-loaderที่พลาด

เมื่อแก้ไขข้อบกพร่องนี้แล้วจะเป็นการดีกว่าที่จะลบesModule: falseและอัปเกรดเพียงhtml-loaderเพราะ ES Modules ให้ประโยชน์เล็กน้อย (ดังที่กล่าวไว้ในเอกสาร )

อีกวิธีหนึ่งถ้า (เช่นฉัน) คุณพบปัญหานี้เนื่องจากคุณประสบปัญหาในการโหลดภาพจาก CSS (แทนที่จะเป็นจาก HTML) การแก้ไขคือเพื่ออัปเกรดcss-loaderไม่จำเป็นต้องปิดใช้งานโมดูล ES


2

สิ่งนี้เกิดขึ้นกับตัวโหลดไฟล์เวอร์ชัน 5.0.2 เวอร์ชันก่อนหน้านี้ทำงานได้ดีโดยไม่ต้องเรียกdefaultคุณสมบัติ


0

เพิ่งอัปเดตตัวโหลดไฟล์ของฉันเป็น ^ 5.0.2 นาทีที่แล้ว

ฉันรู้ว่าesModule: falseเป็นการแก้ไขที่แนะนำ แต่ไม่ได้ผลสำหรับฉัน

การแก้ไขของฉันเป็น<img src={require('assets/logo.png').default}/>สิ่งที่แปลก ครั้งแรกที่ใช้งาน.defaultแต่ใช้งานได้

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.