I am using webpack with HtmlWebpackPlugin
, html-loader
and file-loader
. I have a simple project structure in which I use no frameworks, but only typescript. Thus, I write my HTML code directly to index.html
. I also use this HTML file as my template in HtmlWebpackPlugin
.
As all websites do I need to put an image which refers to a PNG in my assets folder. file-loader
should load the file correctly put the new filename inside the src
tag but that is not what is happening. Instead, as the value of src
tag, I have [object Module]
. I assume the file-loader
emits some object and it is represented like this when its .toString()
method is run. However, I can see that file-loader
has processed the file successfully and emitted with new name to the output path. I get no errors. Here is my webpack configuration and 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>
Project structure:
config/ webpack.config.js dist/ src/ styles/ assets/ logo.png index.html app.ts
Edit 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"
Output | webpack webpack is a module bundler. Its main purpose is to bundle JavaScript files for usage in a browser, yet it is also capable of transforming, bundling, or packaging just about any resource or asset. webpack is a module bundler.
compiler: The current webpack compiler (can be undefined) issuer: The path to the module that is importing the module being loaded realResource: Always the path to the module being loaded resource: The path to the module being loaded, it is usually equal to realResourceexcept when the resource name is overwritten via !=!in request string
webpack is a module bundler. Its main purpose is to bundle JavaScript files for usage in a browser, yet it is also capable of transforming, bundling, or packaging just about any resource or asset. Sponsor webpack and get apparel from the official shop!
Note that, while there can be multiple entry points, only one output configuration is specified. The minimum requirement for the output property in your webpack configuration is to set its value to an object and provide an output.filename to use for the output file (s):
Per the file-loader docs:
By default, file-loader generates JS modules that use the ES modules syntax. There are some cases in which using ES modules is beneficial, like in the case of module concatenation and tree shaking.
It seems that webpack resolves ES module require()
calls to an object that looks like this: {default: module}
, instead of to the flattened module itself. This behavior is somewhat controversial and is discussed in this issue.
Therefore, to get your src
attribute to resolve correctly, you need to be able to access the default
property of the exported module. If you're using a framework, you should be able to do something like this:
<img src={require('assets/logo.png').default}/> <!-- React --> <!-- OR --> <img src="require('assets/logo.png').default"/> <!-- Vue -->
Alternatively, you can enable file-loader's CommonJS module syntax, which webpack will resolve directly to the module itself. Set esModule:false
in your webpack config.
webpack.config.js:
{ test: /\.(png|jpe?g|gif)$/i, use: [ { loader: 'file-loader', options: { esModule: false, }, }, ], },
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With