Reputation: 739
Images are not loading in the browser using Webpack 4 with either of url-loader, or file-loader. Small images are not in data url(or if they are the browser isn't showing them) and file network requests are not being made with file loader.
Nginx is serving the images properly at https://{server}/images/image_name.png
, but not https://{server}
and no network calls for images are being made in web inspector network panel.
Best guess so far is Webpack url-loader or file-loader must not be generating the right URL. Cannot find the host when searching app.bundle.js for the url. I've tried for days every combination of publicPath
, outputPath
, etc.. from all the other stackoverflow posts, nothing works.
Is there any way to view the url's that webpack generates besides searching the js? Is the webpack config not proper? Troubleshooting advice?
Here is how I handle images in code:
import nav_logo from "Images/white_nav_logo.svg";
<img src={nav_logo} />
Here is my webpack.common.js:
module.exports = {
mode: mode,
entry: {
app: ["./src/js/app.js"]
},
output: {
path: path.resolve(__dirname, "dist"),
filename: '[name].bundle.js',
publicPath: '/',
chunkFilename: '[name].bundle.js'
},
module: {
rules: [
{
test: /\.(sc|c|)ss$/,
issuer: {
exclude: /\.less$/,
},
use: [
{
loader: 'style-loader',
options: {
},
},
{
loader: 'css-loader',
options: {
importLoaders: 1,
localIdentName: '[name]-[local]-[hash:base64:5]',
},
},
],
},
{
test: /\.less$/,
use: [
{
loader: 'style-loader',
},
{
loader: 'css-loader',
options: {
importLoaders: 1,
},
},
],
},
{
test: /\.(jsx?)/,
exclude: ["/node_modules", "/src/js/elm"],
use: [
{ loader: "babel-loader?cacheDirectory=true",
}
]
},
{
test: /\.scss$/,
issuer: /\.less$/,
use: {
loader: './src/js/sassVarsToLess.js'
}
},
{
test: /\.(jpe?g|png|gif|svg)$/i,
use: [
{
loader: 'url-loader',
options: {
limit: 10000,
name: 'images/[name].[ext]',
}
},
{
loader: "image-webpack-loader",
options: {
disable: true,
mozjpeg: {
progressive: true,
quality: 65
},
// optipng.enabled: false will disable optipng
optipng: {
enabled: true,
},
pngquant: {
quality: '65-90',
speed: 4
},
gifsicle: {
interlaced: false,
},
// the webp option will enable WEBP
webp: {
quality: 75
}
}
},
],
},
{
test: /\.(ttf|otf|eot|woff2?)$/,
loader: "file-loader",
options: {
name: 'fonts/[name].[ext]',
}
}
],
noParse: [/\.elm$/]
},
node: {
fs: 'empty'
},
plugins: [
new Dotenv(),
new CopyWebpackPlugin([{
from: "./src/assets/css",
to: "css"
},
]),
]
};
and webpack.prod.js
module.exports = merge(common, {
mode: 'production',
module: {
rules: [
{
test: /\.(sc|c|)ss$/,
issuer: {
exclude: /\.less$/,
},
use: [
{
loader: MiniCssExtractPlugin.loader,
},
{
loader: 'css-loader',
options: {
importLoaders: 1,
localIdentName: '[name]-[local]-[hash:base64:5]',
},
},
],
},
{
test: /\.less$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
},
{
loader: 'css-loader',
options: {
importLoaders: 1,
}
},
],
},
{
test: /\.(jsx?)/,
exclude: ["/node_modules", "/src/js/elm"],
use: [
{ loader: "babel-loader?cacheDirectory=true",
}
]
},
{
test: /\.scss$/,
issuer: /\.less$/,
use: {
loader: './src/js/sassVarsToLess.js' // Change path if necessary
}
},
{
test: /\.(jpe?g|png|gif|svg)$/i,
use: [
{
loader: 'url-loader',
options: {
limit: 10000,
name: 'images/[name]-[hash:8].[ext]'
}
},
{
loader: "image-webpack-loader",
options: {
disable: false,
mozjpeg: {
progressive: true,
quality: 65
},
// optipng.enabled: false will disable optipng
optipng: {
enabled: true,
},
pngquant: {
quality: '65-90',
speed: 4
},
gifsicle: {
interlaced: false,
},
// the webp option will enable WEBP
webp: {
quality: 75
}
}
},
],
},
{
test: /\.(ttf|otf|eot|woff2?)$/,
loader: "file-loader",
options: {
name: 'fonts/[name].[ext]',
}
}
],
noParse: [/\.elm$/]
},
optimization: {
minimizer: [new TerserJSPlugin(), new OptimizeCSSAssetsPlugin({})]
},
plugins: [
new HtmlWebpackPlugin({
template: './src/assets/prod.index.html'
}),
new MiniCssExtractPlugin({
filename: '[name].css',
chunkFilename: '[id].css',
}),
],
})
and here is nginx default.conf
server {
listen 80;
server_name <domain_name>;
root /usr/share/nginx/html;
access_log /var/log/nginx/host.access.log main;
index index.html;
location / {
try_files $uri $uri/ =404;
}
location /images/ {
alias /usr/share/nginx/html/images/;
try_files $uri $uri/ =404;
error_log /var/log/nginx/error.log debug;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
Upvotes: 6
Views: 20820
Reputation: 1239
For loading images using url-loader
If you notice inside config/webpack.config.js
There is a module object
which has rules object
inside it.
For the rules or list of rules provided there is limit key
limit key is very important
Significance of limit value
-if the size of image to be loaded is greater than the limit value provided then by default file-loader is used.
e.g
if I have below webpack.config.js
configuration
{
test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/],
loader: require.resolve('url-loader'),
options: {
limit: 10000,
name: 'static/media/[name].[hash:8].[ext]',
},
},
inside my moudules -> rules object
Above the limit value is 10000 bytes so webpack will load only those images using url-loader whose size is less than 10000 bytes if size of image is found equal to or greater than 10000 then file-loader is used by default until fallback loader is not specified.
So suppose if you are dynamically adding a image something like this inside your code.
import largeimage from '../static/images/largeimage.jpg'
or whatever path
and the size of largeimage
is less than the limit value the image will not get loaded.
SOLUTION
For the webpack to load the image using url-loader your largeimage size should be less than limit value.
So either increase limit or decrease size of image.
Reference https://webpack.js.org/loaders/url-loader/#limit
Upvotes: 3
Reputation: 1877
url-loader
is not loading image as separate file, it encodes the file into base64 format and includes it into js bundle. Hence there will be no separate request to the image file. See this answer:
Url-loader vs File-loader Webpack
Try to load images with file-loader
instead. I usually load both fonts and images with file-loader
and it is working correctly.
I am using this working configuration (development):
// this is configured outside of the exported webpack configuration code
const BASE_DIR = resolve(`${__dirname}`);
module.exports = {
mode: 'development',
devtool: 'eval-source-map',
resolve: {
modules: [
resolve(BASE_DIR),
'node_modules'
]
},
output: {
// ...
publicPath: '/'
},
module: {
rules: [
// ...
{
test: /\.(png|svg|jpg|jpeg|gif|tiff)$/,
use: [
'file-loader?name=assets/[name].[ext]'
]
},
// ...
]
}
// ...
}
My image file is physically located at 'src/assets/logo_arc.png' and I am using it this way:
import logo from 'src/assets/logo_arc.png';
// ...
<img src={logo} alt={'company logo'} />
I can see my file located in development build directory under subdirectory assets
as I would expect.
When running application on webopack dev server (on localhost, my custom port 9901) the image is served on address http://localhost:9901/assets/logo_arc.png
.
In the development bundle I can see this involved parts:
// definition of webpack public path
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "/";
// ...
// the image itself as a webpack module
/***/ "./src/assets/logo_arc.png":
/*!*********************************!*\
!*** ./src/assets/logo_arc.png ***!
\*********************************/
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {
eval("module.exports = __webpack_require__.p + \"assets/logo_arc.png\";//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8vLi9zcmMvYXNzZXRzL2xvZ29fYXJjLnBuZz8wMmVlIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLGlCQUFpQixxQkFBdUIiLCJmaWxlIjoiLi9zcmMvYXNzZXRzL2xvZ29fYXJjLnBuZy5qcyIsInNvdXJjZXNDb250ZW50IjpbIm1vZHVsZS5leHBvcnRzID0gX193ZWJwYWNrX3B1YmxpY19wYXRoX18gKyBcImFzc2V0cy9sb2dvX2FyYy5wbmdcIjsiXSwic291cmNlUm9vdCI6IiJ9\n//# sourceURL=webpack-internal:///./src/assets/logo_arc.png\n");
/***/ }),
// importing webpack module into variable, it is used later in the img element
var src_assets_logo_arc_png__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! src/assets/logo_arc.png */ "./src/assets/logo_arc.png");
// ...
// usage in the img element
react__WEBPACK_IMPORTED_MODULE_0__["createElement"]("img", {
src: src_assets_logo_arc_png__WEBPACK_IMPORTED_MODULE_7___default.a,
alt: 'company logo'
}))
Upvotes: 1