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.
Related
I'm creating a small library to power a few of my projects.
I found that i was getting issues inside the client apps with multiple conflicting versions of react when importing my library. This led me to setting both react and react-dom under peer dependencies in the library package.json which fixed the problem.
However, I am trying to run a sandbox environment via a webpack bundler to test and play with components within the library repo as i am working on it (instead of using npm link), and now I am having an issue whereby react is no longer being detected as a local dependency.
Here is my webpack config.
FWIW, when building out the components for production use I am exporting modules via tsconfig, and not using webpack at all. But i'm finding it difficult to resolve this situation of maintaining a test environment :/
const path = require('path');
const webpack = require('webpack');
const HtmlWebPackPlugin = require('html-webpack-plugin');
const isDevelopment = process.env.NODE_ENV !== 'production';
module.exports = {
mode: isDevelopment ? 'development' : 'production',
entry: path.resolve(__dirname, './sandbox/web/index.tsx'),
module: {
rules: [
{
test: /\.tsx?$/,
exclude: /node_modules/,
use: ['babel-loader', 'ts-loader'],
},
{
test: /\.(s(a|c)ss)$/,
use: ['style-loader', 'css-loader', 'sass-loader'],
},
{
test: /\.svg?$/,
loader: 'svg-url-loader',
options: {
limit: 10000,
},
},
],
},
resolve: {
extensions: ['.js', '.jsx', '.tsx', '.ts'],
alias: {
src: path.resolve(__dirname, 'src'),
components: path.resolve(__dirname, 'src/components'),
hooks: path.resolve(__dirname, 'src/hooks'),
themes: path.resolve(__dirname, 'src/themes'),
types: path.resolve(__dirname, 'src/types'),
utils: path.resolve(__dirname, 'src/utils'),
'react-native$': 'react-native-web',
},
},
output: {
path: path.resolve(__dirname, './sandbox/web'),
filename: 'bundle.js',
},
devtool: 'inline-source-map',
watchOptions: {
poll: true,
ignored: '/node_modules/',
},
plugins: [
new HtmlWebPackPlugin({
template: path.resolve(__dirname, './sandbox/web/index.html'),
filename: 'index.html',
}),
new webpack.IgnorePlugin({
resourceRegExp: /^\.\/native$/,
contextRegExp: /src$/,
}),
],
devServer: {
historyApiFallback: {
index: '/',
},
},
};
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 using webpack to build my react app, it's creating 4 Mb size of bundle.js which is very huge. How can I reduce this size? Here is my webpack.config.js, what else plugins should I use?
Here's a list of plugins I'm using, please suggest other plugins that can be helpful to reduce the size of bundle file, or what's wrong with my config.
var compressionPlugin = require('compression-webpack-plugin');
var copyWebpackPlugin = require('copy-webpack-plugin');
var extractTextWebpackPlugin = require('extract-text-webpack-plugin');
var htmlWebpackPlugin = require('html-webpack-plugin');
var path = require('path');
var webpack = require('webpack');
var UglifyJSPlugin = require('uglifyjs-webpack-plugin');
// Setup config.
module.exports = {
devServer: {
port: API === 'local' ? 8081 : 8080
},
devtool: DEBUG ? 'inline-source-map' : false,
entry: [
'whatwg-fetch',
path.join(__dirname, PATH)
],
module: {
loaders: [
{
exclude: /(bower_components|node_modules)/,
loader: 'babel-loader',
query: {
plugins: [
'transform-class-properties',
'transform-object-rest-spread',
'transform-runtime'
],
presets: ['latest', 'react']
},
test: /\.jsx?$/
},
{
test: /\.scss?$/,
use: CssPlugin.extract({
fallback: 'style-loader',
use: ['css-loader', 'sass-loader']
})
},
{
loader: 'worker-loader',
options: {
name: '[name].js',
inline: true
},
test: /\.worker\.js$/
}
]
},
output: {
filename: '[name].bundle.[chunkhash].js',
path: path.join(__dirname, './dist'),
chunkFilename: "[name].[chunkhash].js",
publicPath: '/'
},
plugins: plugins,
resolve: {
extensions: ['.js', '.jsx']
}
};
You should analyse your bundle by using webpack-bundle-analyzer to recognize the reasons.
Then you could split your bundle. I found that react lazy is a good option.
Finally, you could try some webpack plugin to reduce your bundle such as: compression-webpack-plugin, dedupe-plugin, uglifyjs-plugin, ignore-plugin
I am using Webpack to add support for ES6, react and some other things.
Right now I am getting error:
Refused to apply style from http://localhost:5500/bundle.css because its MIME type ('text/html') is not a supported stylesheet MIME type, and strict MIME checking is enabled.
So I checked sources tab in Google Chrome Developer Tools and the bundle.css doesn't even exist. What i am doing wrong ?
Here's my webpack config:
const path = require("path");
const webpack = require("webpack");
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
entry: "./index.js",
output: {
path: path.resolve(__dirname, "/"),
publicPath: "/",
filename: "bundle.js"
},
mode: "development",
module: {
rules: [
{
test: /\.(js\jsx)$/,
exclude: /(node_modules|framework)/,
loader: require.resolve("babel-loader"),
options: { presets: ["#babel/preset-env"] }
},
{
test: /\.css$/,
use: [require.resolve("style-loader"), require.resolve("css-loader")]
},
{
test: /\.scss$/,
use: [
require.resolve("style-loader"),
require.resolve("css-loader"),
require.resolve("sass-loader")
]
}
]
},
resolve: { extensions: ["*", ".js", ".jsx"] },
devServer: {
port: 5500,
host: "<ip address>",
publicPath: "http://localhost:5500",
hotOnly: true
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new HtmlWebpackPlugin({
template: path.resolve(__dirname, "index.html"),
filename: "index.html",
inject: true
})
]
};
By default css is compiled into the js bundle during dev, to extract it out to a file for your prod build in webpack 4 use https://webpack.js.org/plugins/mini-css-extract-plugin/.
Older versions of webpack should use https://github.com/webpack-contrib/extract-text-webpack-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.