unable to load background image on body using webpack 4 in reactjs - reactjs

in my react js app I want to add the background image on the body.it is working fine when I'm doing in development mode but when comes to production it is not working.
for production, I'm using dist separate folder may it is creating some path issue.
here my scss
body {
font-family: Helvetica,Arial,sans-serif;
font-size: $m-size;
height: 100%;
width: 100%;
margin: 0px;
padding: 0px;
background-image: url(/images/bg4.png);
background-attachment: fixed;
background-repeat: no-repeat;
background-position: top;
background-size:cover;
}
my webpack.config
module.exports = {
entry:{
vendor: VENDOR_LIBS,
main: './src/app.js',
},
output: {
path: path.join(__dirname, 'dist'),
filename: '[name].bundle.js',
chunkFilename: '[name].bundle.js',
publicPath: '/',
},
devtool: 'source-map',
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
},
{ test: /\.bundle\.js$/, use: { loader: 'bundle-loader', options: {lazy: true} } },
{
test: /\.s?css$/,
use: [
MiniCssExtractPlugin.loader,
{
loader: 'css-loader?url=false',
options: {
sourceMap: true,
}
},
{
loader: 'sass-loader',
options: {
sourceMap: true
}
}
]
},{
test: /\.(gif|svg|jpg|png|ttf|eot|woff(2)?)(\?[a-z0-9=&.]+)?$/,
loader: "file-loader?name=[name].[ext]",
}
]
},
plugins: [
new CleanWebpackPlugin('dist', {} ),
new MiniCssExtractPlugin({
filename: 'style.[contenthash].css',
}),
new HtmlWebpackPlugin({
inject: true,
hash: true,
template: './src/index.html',
filename: 'index.html',
favicon: './public/images/fav.ico'
}),
new WebpackMd5Hash(),
new webpack.DefinePlugin({
'process.env': {
'NODE_ENV': JSON.stringify('production')
}
}),
],
optimization: {
splitChunks: {
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendor',
chunks: 'all',
minChunks: 2
},
}
},
runtimeChunk: true,
minimizer: [
new UglifyJsPlugin({
cache: true,
parallel: true,
sourceMap: true,
uglifyOptions: {
compress: {
inline: false
}
}
}),
new OptimizeCSSAssetsPlugin({})
],
},
};
webpack generating other images into base64 but not for this image.and it is not available in dist folder.
can any one help me out, i searched lot of questions but couldn't solve.
i don't want any external link to load image.

In production your current directory will change to /dist/index.html so thats why the path you used for development /images/bg4.png can't find the file.
The solution is to copy your static image files, like your background, into the /dist folder in the build process.
Assuming your project directory is similar to the following:
...
/images/bg4.png
package.json
Then add these commands to your webpack build script to copy the images into your production directory /dist.
// in package.json
"scripts": {
...
"build": "...your webpack build commands... && cp -a images\\. dist\\images",
...
},
Your new file directories will look like
/dist/...your index.html, bundles, etc...
/images/bg4.png
/images/bg4.png
package.json
and your image path should find the image file now.

Related

Resolve Relative Path from node_modules to Dist folder with Webpack

I'm using React component as an NPM Package. in the component, I have SCSS file
with url(../iamges/img..) path, but actually, the images folder located in the Dist folder, how can I point Webpack to take the relative path from node_modules and serve it from images folder located in the Dist?
located in node_modules =>
background: url('../images/some-icon.svg') no-repeat center center;
Webpack config:
const webpack = require('webpack');
const path = require('path');
module.exports = {
entry: './src/index.js',
devtool: 'inline-module-source-map',
output: {
path: path.resolve(__dirname, '/dist'),
filename: 'bundle.js',
publicPath: '/',
},
module: {
rules: [
{
test: /\.js$/,
use: {
loader: 'babel-loader',
},
},
{
test: /\.scss$/,
use: [
{ loader: 'style-loader' },
{ loader: 'css-loader' },
{
loader: 'resolve-url-loader',
// options: {
// debug: true,
// root: path.join(__dirname, './dist/images'),
// includeRoot: true,
// absolute: true,
// },
},
{
loader: 'sass-loader',
options: {
sourceMap: true,
sourceMapContents: false,
},
},
],
},
{
test: /\.css$/,
loaders: ['style-loader', 'css-loader'],
},
{
test: /\.(png|jpg|gif|svg|eot|ttf|woff|woff2)$/,
use: {
loader: 'url-loader?name=/images/[name].[ext]',
options: {
limit: 10000,
},
},
},
],
},
resolve: {
extensions: ['.js', '.jsx'],
// modules: [path.resolve(__dirname, '/images'), 'node_modules'],
alias: {
'react-redux': path.resolve('./node_modules/react-redux'),
},
},
plugins: [new webpack.HotModuleReplacementPlugin()],
devServer: {
hot: true,
publicPath: '/dist/',
},
};
babel.config.js
module.exports = {
// presets: ['#babel/preset-env', '#babel/preset-react'],
plugins: [
'#babel/plugin-proposal-class-properties',
'#babel/plugin-proposal-export-default-from',
'#babel/transform-runtime',
],
sourceType: 'unambiguous',
presets: [
[
'#babel/preset-env',
{
targets: {
node: 'current',
},
},
],
'#babel/preset-react',
],
};
dist
-- images
-- index.html
ERROR:
ERROR in ./node_modules/comp/src/styles/details.scss (./node_modules/css-loader!./node_modules/resolve-url-loader!./node_modules/sass-loader/lib/loader.js??ref--5-3!./node_modules/compdetails/src/styles/details.scss)
Module not found: Error: Can't resolve '../images/icon.svg'
Anything referred through url('...') in css will be computed with reference to the path of deployed application (scss will not compute the path unless variable or function is not being used):
For example:
If your referred component SCSS module is having background: url('../images/some-icon.svg') no-repeat center center;
The final CSS compilation will be same (it is also because the component is not using any SCSS variables or functions to compute the final path).
So your application will always try to find that image as:
Example: http://localhost:3000/../images/some-icon.svg which is a problem.
(.. is referred as parent directory)
If you try to run your app with some sub-url (also known as sub context) as http://localhost:3000/sub-url/ and you keep your images parallel to sub-url folder it will automatically work.
-- /
|
|-- sub-url
|
|-- index.html
|-- images
|
|-- some-icon.svg
Another option can be override the component SCSS with yours.
You already found the solution to use resolve-url-loader, but in this case you need to import the component's scss file into you scss.
so your webpack config should look like:
const webpack = require('webpack');
const path = require('path');
module.exports = {
entry: './src/index.js',
devtool: 'inline-module-source-map',
output: {
path: path.resolve(__dirname, '/dist'),
filename: 'bundle.js',
publicPath: '/',
},
module: {
rules: [
{
test: /\.js$/,
use: {
loader: 'babel-loader',
},
},
{
test: /\.scss$/,
use: [
{ loader: 'style-loader' },
{ loader: 'css-loader' },
// CHANGE HERE
{
loader: 'resolve-url-loader',
options: {
root: '/images', // considering all your images are placed in specified folder. Note: this is just a string that will get as prefix to image path
includeRoot: true,
absolute: true,
},
},
{
loader: 'sass-loader',
options: {
sourceMap: true,
sourceMapContents: false,
},
},
],
},
{
test: /\.css$/,
loaders: ['style-loader', 'css-loader'],
},
{
test: /\.(png|jpg|gif|svg|eot|ttf|woff|woff2)$/,
use: {
loader: 'url-loader?name=/images/[name].[ext]',
options: {
limit: 10000,
},
},
},
],
},
resolve: {
extensions: ['.js', '.jsx'],
// modules: [path.resolve(__dirname, '/images'), 'node_modules'],
alias: {
'react-redux': path.resolve('./node_modules/react-redux'),
},
},
plugins: [new webpack.HotModuleReplacementPlugin()],
devServer: {
hot: true,
publicPath: '/dist/',
},
};
I hope it helps.

Build bundle.js in create-react-app application

Made a project. Now we need to collect everything in one bundle.js, and not in the way create-react-app does.
Executed the eject command, configs appeared. But how do i get bundle.js?
It is important that everything that is in the project (styles, pictures, etc.) be gathered into one file.
## My Solution
webpack.config.js:
const path = require("path");
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
context: __dirname,
entry: "./src/index.js",
output: {
path: path.join(__dirname, "/dist"),
publicPath: '',
filename: "widget.js"
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: ["babel-loader"]
},
{
test: /\.css$/,
use: ["style-loader", "css-loader"]
},
{
test: /\.(gif|png|jpe?g|svg|woff(2)?|ttf|eot)$/i,
use: [
{
loader: 'file-loader',
options: {
publicPath: 'img',
outputPath: 'img',
name: '[name].[ext]',
},
},
],
}
]
},
optimization: {
minimizer: [new UglifyJsPlugin({
uglifyOptions: {
warnings: false,
parse: {},
compress: {},
mangle: true,
output: {
comments: false,
},
toplevel: false,
nameCache: null,
ie8: true,
keep_fnames: false,
},
})],
},
plugins: [
new HtmlWebpackPlugin({
template: "./public/index.html"
})
]
};
Ejecting is a real bad solution, instead use rewire npm install react-app-rewired and add a customized build script.
please checkout my answer here
How to build a production version of React without minification?

Production webpack increases size of bundle.js.map

Im trying to create a production build of my code and have made a webpack.production.config.js file. When I run 'webpack -p', my bundle.js file size is reduced but my bundle.js.map file size is increased. Here is the code and respective outputs:
webpack.config.js:
const path = require("path"); //eslint-disable-line
const webpack = require('webpack');
module.exports = {
context: __dirname,
entry: "./frontend/index.jsx",
output: {
path: path.join(__dirname, 'assets', 'build'),
filename: "bundle.js",
devtoolModuleFilenameTemplate: '[resourcePath]',
devtoolFallbackModuleFilenameTemplate: '[resourcePath]?[hash]'
},
externals: {
'cheerio': 'window',
'react/lib/ExecutionEnvironment': true,
'react/lib/ReactContext': true
},
module: {
loaders: [
{
test: [/\.jsx?$/, /\.js?$/],
exclude: /(node_modules|bower_components)/,
loader: 'babel',
query: {
presets: ['es2015', 'react']
}
},
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'eslint-loader'
}
]
},
devtool: 'source-map',
eslint: {
configFile: './.eslintrc'
},
resolve: {
extensions: ["", ".js", ".jsx" ]
},
watchOptions: {
aggregateTimeout: 500,
poll: 2000,
ignored: /node_modules/
}
};
11:22 $ webpack
Hash: 3eaf0c4ed8964deb6866
Version: webpack 1.13.3
Time: 5805ms
Asset Size Chunks Chunk Names
bundle.js 2.16 MB 0 [emitted] main
bundle.js.map 2.53 MB 0 [emitted] main
+ 484 hidden modules
webpack.production.config.js:
const path = require("path"); //eslint-disable-line
const webpack = require('webpack');
module.exports = {
context: __dirname,
entry: "./frontend/index.jsx",
output: {
path: path.join(__dirname, 'assets', 'build'),
filename: "bundle.js",
devtoolModuleFilenameTemplate: '[resourcePath]',
devtoolFallbackModuleFilenameTemplate: '[resourcePath]?[hash]'
},
externals: {
'cheerio': 'window',
'react/lib/ExecutionEnvironment': true,
'react/lib/ReactContext': true
},
module: {
loaders: [
{
test: [/\.jsx?$/, /\.js?$/],
exclude: /(node_modules|bower_components)/,
loader: 'babel',
query: {
presets: ['es2015', 'react']
}
},
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'eslint-loader'
}
]
},
plugins: [
new webpack.DefinePlugin({
'process.env': {
'NODE_ENV': JSON.stringify('production')
}
}),
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: true
}
})
],
devtool: 'cheap-module-source-map',
resolve: {
extensions: ["", ".js", ".jsx" ]
}
};
11:19 $ webpack -p
Hash: c40d4a49c049e8b5a525
Version: webpack 1.13.3
Time: 20990ms
Asset Size Chunks Chunk Names
bundle.js 805 kB 0 [emitted] main
bundle.js.map 5.55 MB 0 [emitted] main
+ 484 hidden modules
Any idea why bundle.js.map increases so significantly and if this is a problem? I also get a bunch of warnings from Uglify.js that I've been told to ignore.
Thanks.
I don't think this is a problem because source-maps are only used for debugging.
Also they are only loaded when devtools are open. Performance impact of using css / javascript source-maps in production
In short it is better to add several plugins (see description at the end) and use section "optimization: {...}" in your webpack.config.js
I have webpack 6.0.1. Based on the documentation I tested, use the following configuration ideas for webpack.config.js. You can test your configuration against these settings:
//webpack.config.js
module.exports = {
...
devtool: 'cheap-module-source-map',
...
plugins : [
...
new webpack.DefinePlugin({ 'process.env.NODE_ENV': JSON.stringify('production') }),
new webpack.optimize.ModuleConcatenationPlugin(),
new webpack.HashedModuleIdsPlugin({
hashFunction: 'sha256',
hashDigest: 'hex',
hashDigestLength: 4
}),
new webpack.optimize.OccurrenceOrderPlugin(),
new webpack.NoEmitOnErrorsPlugin(),
],
...
optimization: {
namedModules: false,
namedChunks: false,
nodeEnv: 'production',
flagIncludedChunks: true,
occurrenceOrder: true,
sideEffects: true,
usedExports: true,
concatenateModules: true,
splitChunks: {
cacheGroups: {
commons: {
test: /[\\/]node_modules[\\/]/,
name: 'vendor',
chunks: 'all'
}
},
minSize: 30000,
maxAsyncRequests: 5,
maxAsyncRequests: 3,
},
noEmitOnErrors: true,
minimize: true,
minimizer: [
// we specify a custom UglifyJsPlugin here to get source maps in production
new UglifyJsPlugin({
cache: true,
parallel: true,
uglifyOptions: {
compress: false,
ecma: 6,
mangle: true
},
sourceMap: true
})
],
removeAvailableModules: true,
removeEmptyChunks: true,
mergeDuplicateChunks: true,
},
...
}
Notes:
webpack.optimize.ModuleConcatenationPlugin() - concatenate the scope
of all your modules into one closure and allow for your code to have
a faster execution time in the browser
webpack.HashedModuleIdsPlugin() - cause hashes to be based on the
relative path of the module, generating a four character string as
the module id
webpack.optimize.OccurrenceOrderPlugin() - vary the
distribution of the ids to get the smallest id length for often used
ids
webpack.NoEmitOnErrorsPlugin() - skip the emitting phase
whenever there are errors while compiling. This ensures that no
assets are emitted that include errors

webpack and less how to include images url in css

Just confused with my webpack and less set up best way to include urls for images in my css and have them working in dev and build mode.
Following worked in dev using webpack-devserver but not after build.
.login-container{
height:100%;
width:100%;
background: url('../../images/home3.jpg') no-repeat center center fixed;
And in my config.
plugins.push(
new HtmlWebpackPlugin({
template: './src/index.html',
inject: 'body'
}),
// Write out CSS bundle to its own file:
new ExtractTextPlugin({
filename: 'css/styles.css',
allChunks: true})
);
Also
entry: {
app: './src/app/app.js'
},
devServer: {
outputPath: path.join(__dirname, 'src'),
contentBase: "./src"
},
output: {
path: path.resolve(__dirname, 'dist'),
publicPath: isProd ? '' : 'http://localhost:8080/',
filename: isProd ? 'js/[name].[hash].js' : 'js/[name].bundle.js',
chunkFilename: isProd ? 'js/[name].[hash].js' : 'js/[name].bundle.js'
},
In dev it worked fine but after build it was trying to load the images from my css folder
i.e. mysites/css/12424324234234234.jpg
instead of
i.e. mysites/12424324234234234.jpg where the images really was.
Here these solutions posted in the following Github issues might help you.
Github Issues 1
Github Issues 2
The workaround for the process can be done as this
The ExtractTextPlugin need to handle a filename like css/[name].css. As workaround you could use [name].css instead.
set { publicPath: '/' } so that each reference becomes root relative.
OR
you can also use url-loader
You can also check this committed posted by sokra
code loaders: [
{ test: /\.css$/, loader: ExtractTextPlugin.extract(
"style-loader",
"css-loader?sourceMap"
"css-loader?sourceMap",
{
publicPath: "../"
}
)},
{ test: /\.png$/, loader: "file-loader" }
]
},
plugins: [
new ExtractTextPlugin("[name].css?[hash]-[chunkhash]-[name]", {
new ExtractTextPlugin("css/[name].css?[hash]-[chunkhash]-[name]", {
disable: false,
allChunks: true
}),

Specify destination folder in url-loader for webpack

I have images path in css like url(images/image1.jpg) and the loader is defined as
{ test: /\.(png|woff|woff2|eot|ttf|svg|jpg)$/, loader: 'url-loader?limit=1&name=images/[name].[ext]' },
The issue I am facing is that after build process the images are copied to respective folder but the path is pointing to images/image1.jpg relative to the css file location. I want it to be relative to the root directory.
I tried adding a leading / in the name query parameter and it partially fixed the issue
{ test: /\.(png|woff|woff2|eot|ttf|svg|jpg)$/, loader: 'url-loader?limit=1&name=images/[name].[ext]' },
but when I move my files into a sub folder it still points to the root of the domain instead of the folder.
Can you tell me what I am missing in the configuration?
Here is the webpack configuration
'use strict';
var webpack = require('webpack'),
HtmlWebpackPlugin = require('html-webpack-plugin'),
OpenBrowserPlugin = require('open-browser-webpack-plugin'),
ExtractTextPlugin = require('extract-text-webpack-plugin'),
path = require('path'),
srcPath = path.join(__dirname, 'src'),
jsDestPath = 'scripts/';
module.exports = {
target: 'web',
cache: true,
entry: {
common: ['react', 'react-router', 'alt', 'es6-promise'],
offline: path.join(srcPath, 'libs/offline.min.js'),
materialize: path.join(srcPath, 'libs/materialize.js'),
css3_animate_it: path.join(srcPath, 'libs/css3-animate-it.js'),
app: path.join(srcPath, 'App.js')
},
resolve: {
root: srcPath,
extensions: ['', '.js'],
modulesDirectories: ['node_modules']
},
output: {
path: path.join(__dirname, 'build'),
publicPath: '',
filename: jsDestPath + '[name].js',
library: ['Example', '[name]'],
pathInfo: true
},
module: {
loaders: [
{
test: /\.js?$/,
exclude: /node_modules/,
loader: 'babel?cacheDirectory'
},
{
test: /\.css$/,
loader: ExtractTextPlugin.extract("style-loader", "css-loader")
},
/*{
test: /\.(png|woff|woff2|eot|ttf|svg|jpg)$/,
loader: 'url-loader?limit=5' // inline base64 URLs for <=8k images, direct URLs for the rest
},*/
{ test: /\.(png|woff|woff2|eot|ttf|svg|jpg)$/, loader: 'url-loader?limit=1&name=images/[name].[ext]' },
{
test: /\.rt/,
loader: "react-templates-loader"
}
],
},
plugins: [
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery",
"window.jQuery": "jquery"
}),
new webpack.optimize.CommonsChunkPlugin('common', jsDestPath + 'common.js'),
new webpack.optimize.UglifyJsPlugin({minimize: true}),
new HtmlWebpackPlugin({
inject: true,
template: 'src/index.html'
}),
new OpenBrowserPlugin({
url: 'http://localhost:8080',
browser: 'Chrome'
}),
new webpack.NoErrorsPlugin(),
new ExtractTextPlugin("styles/style.css", {
allChunks: true
})
],
debug: true,
//devtool: 'eval-source-map',//'eval-cheap-module-source-map',
devServer: {
contentBase: './build',
historyApiFallback: true
}
};
Remove publicPath: '', or set it to publicPath: '/', and require images
like this let imgSrc = require('../../img/image.png'); via relative paths(from where you are trying to require images).
It should get resolved as {publicPath}/images/[name].[ext]
I hope it should work.
You need to prefix your image URL with ~, otherwise it will be treated as relative to the CSS path. The ~ triggers webpack's normal module resolution. More info in the CSS loader docs here.

Resources