Related
My webpack.config.js file
const path = require('path');
const HtmlWebPackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
module.exports = {
entry: {
index: './src/js/index.js',
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: ['babel-loader'],
},
{
test: /\.html$/,
use: [
{
loader: 'html-loader',
options: { minimize: true },
},
],
},
{
test: /\.(jpg|png)$/,
use: {
loader: 'url-loader',
},
},
{
test: /\.(css|scss)$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
'postcss-loader',
'sass-loader',
],
},
],
},
output: {
path: path.resolve(__dirname, './dist'),
filename: './js/[name].bundle.js',
},
plugins: [
new HtmlWebPackPlugin({
template: path.resolve(__dirname, './src/index.html'),
filename: 'index.html',
chunks: ['index'],
}),
new CleanWebpackPlugin(),
new MiniCssExtractPlugin({
filename: './css/[name].css',
}),
new CopyWebpackPlugin({
patterns: [{ from: './src/assets', to: './assets' }],
}),
],
devtool: 'source-map',
mode: 'development',
};
my files structure where the problem occurs:
what is strange, when I run npm run build in the terminal, all directories are loaded correctly I mean: background-image works, and slider directory with images is loaded, but there is also loaded some additional files with random numerical names
and those three additional .png files are loaded to my index.html as img1.png img2.png and img3.png files which not work on my website, they just do not want to load
This is caused by Webpack 5's new Asset Modules. You can either remove url-loader and specify the asset type like so:
{
test: /\.(jpg|png)$/,
type: 'asset/inline',
},
Or you can disable asset modules by adding type: 'javascript/auto' to your rule:
{
test: /\.(jpg|png)$/,
use: {
loader: 'url-loader',
},
type: 'javascript/auto'
}
See the documentation to learn more, and to see how to do this for file-loader and raw-loader as well.
I think your image files are probably double-processed, because you once just copy your assets folder to your dist output folder, and then you somewhere probably use the images with url("./someImage") or similar in your css files, which get processed by your css loader or css Mini Exctract plugin, which creates that cryptic image asset output, that then gets used in your html files, look at here: webpack.js.org/guides/asset-management/#loading-images.. I dont know why you need to copy your assets folder but that looks redundant to me...
EDIT: I'm not an expert at this, but after investigating some hours into this weird error, I realized that the paths were set correctly to the image files, but the image output that file-loader or other loaders generate with the image (like 0f9b8be78d378ad2ef78.jpg) seems to be something different, if I open them in vscode editor in standard text/binary editor, I get this line: export default __webpack_public_path__ + "someimage.jpg";, with url-loader its the binary64 converted string with data-url(..).. so it seems its not for the purpose to use it in static html files..
I then used the recommended way to do it like this in webpack.config.js:
{ test: /\.(jpg|png)$/,
type: 'asset/resource', }
after that my image was shown correctly, I have no idea what file-loader etc. is doing..
here is my final webpack.config.js:
const path = require('path')
const HtmlWebPackPlugin = require('html-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
module.exports = {
entry: {
index: './src/js/index.js',
},
devServer: {
port: 5757,
contentBase: path.resolve(__dirname, 'src'),
publicPath: '/src',
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: ['babel-loader'],
},
{
test: /\.html$/,
use: [
{
loader: 'html-loader',
options: { minimize: true },
},
],
},
{
test: /\.(jpg|png)$/,
type: 'asset/resource',
},
{
test: /\.(css|scss)$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
'postcss-loader',
'sass-loader',
],
},
],
},
output: {
path: path.resolve(__dirname, './build'),
//publicPath: './assets/images',
},
plugins: [
new HtmlWebPackPlugin({
template: path.resolve(__dirname, './src/index.html'),
filename: 'index.html',
inject: 'body',
}),
new MiniCssExtractPlugin({
filename: './css/[name].css',
}),
],
devtool: 'source-map',
mode: 'development',
}
I have just solved my every problem because after using the answer from #ChillaBee, images were working correctly expect my background photo which I used in css file as url. Use the answer above but change
{
test: /\.(jpg|png)$/,
type: 'asset/resource',
},
to
{
test: /\.(jpg|png)$/,
type: 'asset/inline',
},
now images from html and css are loaded correctly
I am trying my hand at a multipage webpack configuration and have a question about how to load images differently for a landing page compared to the other pages on the site. The landing page builds to the root directory, while the other pages build to their respective subfolders.
Webpack appends the correct relative path ../images/ for the other pages, however the landing page needs to remain as images/, as it is located on the root directory along with the images folder.
How can I configure webpack such that <img src="images/00.jpg"> stays the same for the landing page, but is updated to <img src="../images/00.jpg"> for all other pages?
Here is the source folder:
/ src /
-home.html
-about.html
js/
-home.js
-about.js
images/
-00.jpg
-01.jpg
scss/
-style.scss
Here is the build folder webpack generates:
/ public_html /
-index.html // relative links in this file become broken :(
-bundle.js
about/
-index.html
-bundle.js
images/
-00.jpg
-01.jpg
css/
-style.css
Finally, here is the webpack configuration. Please excuse the wall of code, I decided to include the entire configuration in case there is a better way to set this up.
// webpack.config.js
const webpack = require('webpack');
const path = require('path');
const HtmlWebPackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
module.exports = {
entry: {
home: './src/js/home.js',
about: './src/js/about.js',
},
output: {
filename: (pathData) => {
return pathData.chunk.name === 'home' ? 'bundle.js' : '[name]/bundle.js';
},
path: path.resolve(__dirname, 'public_html')
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
},{
test: /\.html$/,
use: [
{
loader: "html-loader",
options: { minimize: true }
}
]
},{
test: /\.css$/,
use: [MiniCssExtractPlugin.loader, "css-loader"]
},{
test: /\.sass$|\.scss$/,
use: [
MiniCssExtractPlugin.loader,
{ loader: 'css-loader' },
{ loader: 'sass-loader' },
],
},{
test: /\.(jpg|png|svg)$/,
use: [
{
loader: 'file-loader',
options: {
name: '[name].[ext]',
outputPath:'images/',
publicPath:'../images/' // how to exclude home.html ?
}
}
]
}
]
},
plugins: [
new HtmlWebPackPlugin({
hash: true,
filename: 'index.html', // landing page remains in root directory
template: 'src/index.html',
chunks: ['home']
}),
new HtmlWebPackPlugin({
hash: true,
filename: 'about/index.html', // all other pages move to subdirectories
template: 'src/about.html',
chunks: ['about']
}),
new MiniCssExtractPlugin({
filename: "css/style.css"
}),
new CleanWebpackPlugin()
]
};
Thank you! And also, let me know how you like this configuration file!
I have it working. horray!
I never ended up using publicPath. Maybe there would have been a way to change it, but this ended up being a red herring. Instead I restructured my src directory to follow the pattern I was looking for, and removed html-loader so the paths wouldn't get changed during the build process.
Here is my new source directory:
/ src /
-home.html
templates/
-about.html
js/
-home.js
-about.js
images/
-00.jpg
-01.jpg
scss/
-style.scss
You can see home.html is purposely on the main directory rather than in /templates. Image sources are referenced as images/ in home.html, and ../images/ elsewhere.
Now instead of html-loader, I used copy-webpack-plugin to require / copy the images from the source directory to the build folder, as html-loader was changing the paths during the build process. It took me a few tries to figure out that html-loader was the culprit.
Here is my final working webpack config for the record.
// webpack.config.js
const webpack = require('webpack');
const path = require('path');
const HtmlWebPackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const CopyPlugin = require('copy-webpack-plugin');
module.exports = {
context: path.resolve(__dirname, 'src'),
entry: {
home: './js/home.js',
about: './js/about.js',
},
output: {
filename: (pathData) => {
return pathData.chunk.name === 'home' ? 'bundle.js' : '[name]/bundle.js';
},
path: path.resolve(__dirname, 'public_html')
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
},{
test: /\.css$/,
use: [MiniCssExtractPlugin.loader, "css-loader"]
},{
test: /\.sass$|\.scss$/,
use: [
MiniCssExtractPlugin.loader,
{ loader: 'css-loader' },
{ loader: 'sass-loader' },
],
},{
test: /\.(jpg|png|svg)$/,
use: [
{
loader: 'file-loader',
options: {
name: '[path][name].[ext]'
}
}
]
}
]
},
plugins: [
new CopyPlugin({
patterns: [
{from:'./image',to:'image'}
],
}),
new HtmlWebPackPlugin({
hash: true,
filename: 'index.html', // landing page remains in root directory
template: 'index.html',
chunks: ['home']
}),
new HtmlWebPackPlugin({
hash: true,
filename: 'about/index.html', // all other pages move to subdirectories
template: 'templates/about.html',
chunks: ['about']
}),
new MiniCssExtractPlugin({
filename: "style.css"
}),
new CleanWebpackPlugin()
]
};
I solve the problem on this Way.
Import images on views
Import YourImage from '../../public/assets/img/your-image.png';
Call where you need with implement them
src={YourImage}
Or in your classNames
background-image: `url(${YourImage})`
Config the path to your project repository from GitHub in the rules section of webpack.config.js file.
Repository: "https://maikpwwq.github.io/your-repository/"
rules: [ { type: "asset", test: /\.(png|svg|jpg|gif|jpeg)$/i, use: [{ options: { publicPath: '/your-repository/'}, loader: 'file-loader' ]} } ]
Trying to load a CSS background image, defined in SCSS, and serving via WebPack devServer.
The background image defined in SCSS is picked up by WebPack, but it doesn't show on the page.
I have tried setting publicPath option in MiniCssExtractPlugin.loader and looked at all the answers I could find related to this problem, but haven't been able to get this to work.
Update: Also tried setting publicPath option in file-loader. According to the documentation this defaults to the output publicPath, which is the same in my case.
Update: When using an absolute path in SCSS it compiles to CSS as that exact path, but that isn't going to work as local dev and staging and prod all have different paths.
Relevant part of the output when running webpack-dev-server:
Child mini-css-extract-plugin node_modules/css-loader/index.js??ref--5-1!node_modules/sass-loader/dist/cjs.js??ref--5-2!index.scss:
Asset Size Chunks Chunk Names
pages/index/404#2x.png 29.2 KiB [emitted]
index.scss:
body {
background: url("./pages/index/404#2x.png");
}
CSS output:
body {
background: url([object Module]);
}
My WebPack config:
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const path = require('path');
const outputDir = 'dist/website';
const publicPath = '/web/website/';
module.exports = {
mode: 'development',
devtool: 'source-map',
entry: './index.ts',
output: {
path: path.resolve(__dirname, outputDir),
publicPath: publicPath,
filename: 'bundle.js',
},
resolve: {
extensions: ['.ts', '.js'],
},
module: {
rules: [
{
test: /\.ts$/,
use: ['ts-loader'],
},
{
test: /\.scss$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
},
{
loader: 'css-loader',
options: {
sourcemap: true,
},
},
{
loader: 'sass-loader',
options: {
sourceMap: true,
},
},
],
},
{
test: /\.(png|jpe?g|gif|svg|webp)$/i,
use: [
{
loader: 'file-loader',
options: {
name: '[path][name].[ext]',
},
},
],
},
],
},
plugins: [
new MiniCssExtractPlugin({
path: path.resolve(__dirname, outputDir),
filename: '[name].css',
chunkFilename: '[id].css',
}),
new CleanWebpackPlugin([outputDir]),
],
devServer: {
contentBase: path.join(__dirname, outputDir),
publicPath: publicPath,
port: 9009,
proxy: {
'/': 'http://127.0.0.1:5000/',
},
},
};
index.ts:
import './index.scss';
console.log('WebPack is working!');
I have figured out the issue: css-loader was on version 1.0.0. Probab ly because it was installed a long time ago.
Upgrading to the latest version of css-loader with npm install css-loader#latest --save-dev solved the issue.
Been trying to research this but it doesn't seem as if any else has this, or see this as an issue.
I am using mini-css-extract-plugin(MiniCssExtractPlugin) in my webpack.config.js.
However, when I run webpack the console is littered with hundreds of instances of something similar to this...
Child mini-css-extract-plugin ../../../node_modules/css-loader/index.js??ref--6-1!../../../node_modules/postcss-loader/src/index.js!../../../node_modules/sass-loader/lib/loader.js!ui/radiolist-toggler/RadioListToggler.scss:
Entrypoint mini-css-extract-plugin = *
[../../../node_modules/css-loader/index.js?!../../../node_modules/postcss-loader/src/index.js!../../../node_modules/sass-loader/lib/loader.js!./ui/radiolist-toggler/RadioListToggler.scss] /Users/~~~/git/user-section/node_modules/css-loader??ref--6-1!/Users/~~~/git/user-section/node_modules/postcss-loader/src!/Users/~~/git/user-section/node_modules/sass-loader/lib/loader.js!./ui/radiolist-toggler/RadioListToggler.scss 5.33 KiB {mini-css-extract-plugin} [built]
+ 1 hidden module
I need to scroll up for a good few seconds to be able to see all my assets etc.
I am pretty new to webpack, so not exactly sure how to prevent this from being output to the console?
Below is my webpack.config.js
const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const OptimizeCssAssetsPlugin = require("optimize-css-assets-webpack-plugin");
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
const modernizr = require("modernizr");
const CopyWebpackPlugin = require('copy-webpack-plugin');
const CompressionPlugin = require('compression-webpack-plugin');
module.exports = {
context: path.resolve(__dirname, 'src/main/client'),
entry: './index',
devtool: 'cheap-module-source-map',
optimization: {
minimizer: [
new UglifyJsPlugin({
cache: true,
parallel: true,
uglifyOptions: {
mangle: true,
compress: true,
ecma: 6
},
sourceMap: true
}),
new OptimizeCssAssetsPlugin({}),
],
splitChunks: {
chunks: 'all'
}
},
plugins: [
new CompressionPlugin({
test: /\.js$|\.css$|\.html$|\.(png|svg|jpg|gif)$/,
cache: true,
filename: '[path].gz[query]',
algorithm: 'gzip',
threshold: 10240
}),
new CleanWebpackPlugin([
'./target/webapp'
]),
new HtmlWebpackPlugin({
template: './index.html',
filename: '../index.html',
xhtml: true
}),
new MiniCssExtractPlugin({
filename: "[name].css",
}),
new CopyWebpackPlugin([{
from: '../webapp/**/*',
to: '../'
}]),
new webpack.DefinePlugin({
'process.env.NODE_ENV': '"production"'
}),
],
output: {
publicPath: '/app/',
filename: '[name].bundle.js',
chunkFilename: '[id].js',
path: path.resolve(__dirname, 'target/webapp/app/')
},
module: {
rules: [{
loader: "webpack-modernizr-loader",
test: /\.modernizrrc\.js$/
},
{
test: /\.html$/,
exclude: /node_modules/,
use: {
loader: 'html-loader'
}
},
{
test: /\.s?css$/,
use: [
MiniCssExtractPlugin.loader,
{
loader: 'css-loader',
options: {
importLoaders: 1
}
},
{
loader: 'postcss-loader'
},
{
loader: 'sass-loader'
}
]
},
{
test: /\.(png|svg|jpg|gif)$/,
use: [
'file-loader'
]
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
use: [{
loader: 'file-loader',
options: {
name: '[name].[ext]',
outputPath: './assets/fonts/'
}
}]
},
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
loader: "babel-loader",
options: {
presets: ["#babel/env"]
}
}
],
},
resolve: {
alias: {
// You can add comment "Please do not delete this file" in this file
modernizr$: path.resolve(__dirname, "./.modernizrrc.js")
}
}
}
#mcclosa mentioned this as a comment but in case anyone should look at this question, see no answer and click away, the solution is to add the stats option to your webpack.config.js file as follows:
module.exports = {
stats: { children: false },
}
The above option uses the children: false option suggested by #mcclosa, which does successfully remove the junk output by mini-css-extract-plugin, but I find using the preset stats: "minimal" produces a much nicer overall output. Using:
module.exports = {
stats: "minimal",
}
..gives me the following tiny output whenever my build has no errors:
i 「wdm」: Compiling...
i 「wdm」: 69 modules
i 「wdm」: Compiled successfully.
..as opposed to dozens of lines of useless build data, but it will continue to give give error information when errors are present.
Unfortunately, mini-css-extract-loader does not have a setting to control the verbosity of its log output.
Setting stats.children to false or "minimal" in your webpack.config.js can remove a lot of other useful output like your bundle names and sizes, entry point information, time taken to build, legitimate warnings and errors from other plugins that you may want to keep, etc.
Instead it seems that we must add a plugin that executes on the compiler's done hook to remove items from the stats.compilation object associated with mini-css-extract-plugin.
This example plugin should work:
class CleanupMiniCssExtractPlugin {
apply(compiler) {
compiler.hooks.done.tap("CleanupMiniCssExtractPlugin", stats => {
if (this._children) {
const children = stats.compilation.children;
if (Array.isArray(children)) {
stats.compilation.children = children.filter(
child => child.name.indexOf("mini-css-extract-plugin") == -1
);
}
}
});
}
}
Or you can use this npm package: https://www.npmjs.com/package/cleanup-mini-css-extract-plugin
For the open source site, ReForum, I'm trying to update the site to the latest components (ie: webpack 4, react 16, etc). I started with babel and it upgraded smoothly. Then moved to webpack. I spent more than 10 hours trying various configs until I finally got it to compile using the following:
/**
* module dependencies for webpack dev configuration
* Proper webpack dev setup:
* https://medium.freecodecamp.org/how-to-develop-react-js-apps-fast-using-webpack-4-3d772db957e4
*/
const path = require('path');
const webpack = require('webpack');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const autoprefixer = require('autoprefixer');
// define paths
const nodeModulesPath = path.resolve(__dirname, '../node_modules');
const buildPath = path.resolve(__dirname, '../public', 'build');
const mainAppPath = path.resolve(__dirname, '../frontend', 'App', 'index.js');
const sharedStylesPath = path.resolve(__dirname, '../frontend', 'SharedStyles');
const componentsPath = path.resolve(__dirname, '../frontend', 'Components');
const containersPath = path.resolve(__dirname, '../frontend', 'Containers');
const viewsPath = path.resolve(__dirname, '../frontend', 'Views');
/**
* webpack development configuration
*/
module.exports = {
mode: 'development',
target: 'web',
devtool: 'inline-source-map',
entry: [
'webpack-hot-middleware/client',
mainAppPath,
],
output: {
filename: 'bundle.js',
path: buildPath,
publicPath: '/build/',
},
plugins: [
new MiniCssExtractPlugin({
// Options similar to the same options in webpackOptions.output
// both options are optional
filename: '[name].css',
chunkFilename: '[id].css',
}),
new webpack.HotModuleReplacementPlugin(),
],
module: {
rules: [
{
test: /\.js$/,
use: [ 'babel-loader' ],
exclude: [nodeModulesPath],
},
{
test: /\.(sa|sc|c)ss$/,
use: [
'style-loader',
'css-loader',
// 'postcss-loader',
{ loader: 'postcss-loader',
options: {
sourceMap: true,
plugins() {
return [autoprefixer('last 5 version')];
},
// plugins: () => [require('autoprefixer')({
// 'browsers': ['> 1%', 'last 5 versions'],
// })],
},
},
'sass-loader',
],
},
{ test: /\.(png|jpg)$/, use: ['url-loader?limit=8192'] },
{ test: /\.svg$/, use: ['url-loader?limit=10000&mimetype=image/svg+xml'] },
],
},
resolve : {
// automatically resolve file extensions (ie import File from '../path/file')
extensions: ['.js', '.css'],
// alias to call specified folders
alias: {
SharedStyles: sharedStylesPath,
Components: componentsPath,
Containers: containersPath,
Views: viewsPath,
},
},
};
Original Webpack 1 dev config
However, the React elements classname disappear, preventing the styles from being applied. It should be like:
But instead is:
Also, the head now have multiple <style>s .
Please help me get classnames to reappear and fix the multiple head style elements.
FYI, the only way I was able to get postcss-loader to run is by turning it into an object. It would fail with errors like "Error: No PostCSS Config found in ... "
Update 1:
Tried #noppa and #Alex Ilyaev suggestions the following but it didn't work.
{
test: /\.(sa|sc|c)ss$/,
use: [
'style-loader',
// 'css-loader',
{
loader: 'css-loader',
options: {
modules: true,
loaders: true,
importLoaders: 1,
localIndentName:'[name]__[local]___[hash:base64:5]',
},
},
// 'postcss-loader',
{ loader: 'postcss-loader',
options: {
sourceMap: 'inline',
options: {
ident: 'postcss',
plugins: (loader) => [
require('autoprefixer')(),
],
},
},
},
],
},
If you're using Webpack 4, start with no config file - that's right - no config file. WP4 includes sane defaults so most of your non webpack related issues will surface right there.
Regarding the multiple styles block, you need to switch to mini-css-extract-plugin (doesn't support HMR) or extract-css-chunks-webpack-plugin (supports HMR).
Also, note that during dev mode, you'll see multiple style blocks (for HMR). But production build should not have multiple style blocks.