I have in my index.ejs file (you can consider this the .html file) a classic tag <img> that I'm copying in the dist folder with copy-webpack-plugin.
My problem is that in 'production' mode I add an hash to my image instead in the index.ejs file the attribute src of the <img> still will point to the image without the hash. Thus my index.html in the dist folder doesn't display the image.
This is my project :
https://github.com/cuccagna/Webpack28
For convenience, I put here the package.json, the webpack.production.config.js and the index.ejs files:
webpack.production.config.js:
const pathM = require('path');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
/* const { CleanWebpackPlugin } = require('clean-webpack-plugin');
*/
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
entry: './src/js/index.js',
output: {
filename: 'js/bundle.[contenthash].js',
path: pathM.resolve(__dirname, './dist'),
assetModuleFilename: '[path][name].[contenthash][ext]',
publicPath: './',
clean: true /* {
dry: false,
keep:/\.css$/
} */ //Serve per cancellare la cartella dist dalla precedente esecuzione
},
mode: 'production',
module: {
rules:[
{
test: /\.(png|jpe?g|webp|avif|gif|svg)$/,
type: 'asset',
parser: {
dataUrlCondition: {
maxSize: 3 * 1024 //3 Kilobytes QUI CAMBIA LA SOGLIA A 3 KByte
}
}
},
{
test: /\.css$/,
use: [MiniCssExtractPlugin.loader,'css-loader']
},
{
test: /\.scss$/,
use: [MiniCssExtractPlugin.loader,'css-loader','sass-loader']
},
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: [['@babel/env', {
targets: "> 0.1%, not dead",
debug:true,
useBuiltIns: 'usage',
//Puoi mettere anche solo version:3
//La versione la puoi prelevare da package.json
corejs:{version:3.26 , proposals:true}
}]],
//plugins: ['@babel/plugin-proposal-class-properties']
}
}
}
]
},
plugins: [
new CopyWebpackPlugin({
patterns: [
{ from: './assets/img', to: './assets/img/[name].[contenthash][ext]' },
],
options: {
concurrency: 100,
}
}),
new MiniCssExtractPlugin({
filename:"css/main.[contenthash].css"
}),
new HtmlWebpackPlugin({
inject: false,
template: "./index.ejs", //Puoi mettere anche un file html
minify:true
})
]
}
package.json
{
"name": "project5",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"build": "webpack --progress --profile --config webpack.production.config.js",
"dev":"webpack --progress --profile --config webpack.dev.config.js",
"watch": "webpack --progress --profile --watch"
},
"watch": {
"build": "./src"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@babel/core": "^7.20.5",
"@babel/preset-env": "^7.20.2",
"babel-loader": "^9.1.0",
"copy-webpack-plugin": "^11.0.0",
"css-loader": "^6.7.3",
"html-webpack-plugin": "^5.5.0",
"mini-css-extract-plugin": "^2.7.2",
"npm-watch": "^0.11.0",
"sass": "^1.56.2",
"sass-loader": "^13.2.0",
"style-loader": "^3.3.1",
"webpack": "^5.75.0",
"webpack-cli": "^5.0.1"
},
"dependencies": {
"core-js": "^3.26.1"
}
}
index.ejs
<!DOCTYPE html>
<html>
<head>
<title>Custom insertion example</title>
<!-- prettier-ignore -->
<% if (process.env.NODE_ENV === 'production'){%>
<% for(var i=0; i < htmlWebpackPlugin.files.css.length; i++) {%>
<link
type="text/css"
rel="stylesheet"
href="<%= htmlWebpackPlugin.files.css[i] %>"
/>
<% } }%>
</head>
<body>
<img src="./assets/img/natura.jpg" alt="Natura.jpg" />
<img src="./assets/img/natale.jpg" alt="Natale.jpg" />
<button class="hello-world-button">Ciao</button>
<img id="asset-resource" />
<% for(var i=0; i < htmlWebpackPlugin.files.js.length; i++) {%>
<script
type="text/javascript"
src="<%= htmlWebpackPlugin.files.js[i] %>"
></script>
<% } %>
</body>
</html>
A similar problem is described here:
https://github.com/webpack-contrib/copy-webpack-plugin/issues/279
I tried to fix the problem from myself but I can't figure how to proceed.
A solution without any additional webpack loaders and plugins. We can use
compilation, the webpack compilation object to get the assets bycompilation.assetsproperty.The
loadAssetfunction can be used in HTML template to load the bundled asset by its filename.For example:
loadAsset('./assets/img/icons8-apple-50.png')will return./asserts/img/icons8-apple-50.be319f9e64e51eba6ea0.png.E.g.
project structure:
src/index.html:webpack.config.js:We also use
templateParametersoption ofhtml-webpack-pluginto expose theloadAssetfunction to HTML template.Build logs:
As you can see, the key of
compilation.assetsis the filename of assets.Output:
dist/index.html:package.json:After building, run
npm startto start a HTTP server to verify: