How to Load Image Files with Webpack File-Loader

How to load image files with webpack file-loader

Regarding problem #1

Once you have the file-loader configured in the webpack.config, whenever you use import/require it tests the path against all loaders, and in case there is a match it passes the contents through that loader. In your case, it matched

{
test: /\.(jpe?g|png|gif|svg)$/i,
loader: "file-loader?name=/public/icons/[name].[ext]"
}

// For newer versions of Webpack it should be
{
test: /\.(jpe?g|png|gif|svg)$/i,
loader: 'file-loader',
options: {
name: '/public/icons/[name].[ext]'
}
}

and therefore you see the image emitted to

dist/public/icons/imageview_item_normal.png

which is the wanted behavior.

The reason you are also getting the hash file name, is because you are adding an additional inline file-loader. You are importing the image as:

'file!../../public/icons/imageview_item_normal.png'.

Prefixing with file!, passes the file into the file-loader again, and this time it doesn't have the name configuration.

So your import should really just be:

import img from '../../public/icons/imageview_item_normal.png'

Update

As noted by @cgatian, if you actually want to use an inline file-loader, ignoring the webpack global configuration, you can prefix the import with two exclamation marks (!!):

import '!!file!../../public/icons/imageview_item_normal.png'.

Regarding problem #2

After importing the png, the img variable only holds the path the file-loader "knows about", which is public/icons/[name].[ext] (aka "file-loader? name=/public/icons/[name].[ext]"). Your output dir "dist" is unknown.
You could solve this in two ways:

  1. Run all your code under the "dist" folder
  2. Add publicPath property to your output config, that points to your output directory (in your case ./dist).

Example:

output: {
path: PATHS.build,
filename: 'app.bundle.js',
publicPath: PATHS.build
},

webpack file-loader does not load background image

Adding esModule: false inside the url-loader options the image helped me, though I'm not sure why, if someone has the same issue you should try this trick.

How to use webpack with static image files?

Webpack has a file-loader which will handle copying static dependencies and resolving their URLs correctly:

https://webpack.js.org/loaders/file-loader/

Here is more in depth discussion about images specifically: https://webpack.js.org/guides/asset-management/#loading-images

How to load images in webpack 5 without using JavaScript

For all those who have a similar problem. You must first load the html-loader to be able to load images in your HTML files.

How to import every image with file-loader on React

Webpack V5:

  • Use require.context() to load all modules in a directory dynamically. This means you can load all .svg modules dynamically. You don't have to import them one by one.

  • file-loader is DEPRECATED for v5, migrate to Asset Modules to allows one to use asset files (fonts, icons, etc) without configuring additional loaders.

Directory structure:

⚡  tree -L 5 -I 'node_modules'
.
├── dist
│ ├── app.js
│ ├── icon_truck1..svg
│ ├── icon_truck2..svg
│ └── icon_truck3..svg
├── package-lock.json
├── package.json
├── src
│ ├── app.js
│ └── assets
│ └── icon
│ ├── icon_truck1.svg
│ ├── icon_truck2.svg
│ └── icon_truck3.svg
└── webpack.config.js

4 directories, 11 files

src/app.js:

function importAll(images) {
images.keys().forEach((image) => {
console.log(image);
});
}

const images = require.context("./assets/icon", true, /\.svg$/);
importAll(images);

webpack.config.js:

const path = require("path");

module.exports = {
mode: "development",
entry: "./src/app.js",
output: {
filename: "app.js",
path: path.resolve(__dirname, "dist"),
publicPath: "",
},
module: {
rules: [
{
test: /\.(png|svg)$/i,
type: "asset/resource",
generator: {
filename: "[name].[ext]",
},
},
],
},
};

Execution result:

⚡  node dist/app.js
./icon_truck1.svg
./icon_truck2.svg
./icon_truck3.svg

Since you are using React-boilerplate, try to use require.context() like above directly.

file-loader creating extra file in root of dist folder

In the end it looks as if it was the css loader that was causing the issue - so I configured it to ignore urls and then changed from the file-loader plugin to the copy-webpack-plugin to copy the images:

Ignore urls with css loader

      MiniCssExtractPlugin.loader,
{
// Use the css-loader to parse and minify CSS imports.
loader: 'css-loader',
options: {
sourceMap: true,
url: false,
}
},

Copy webpack plugin to copy images

const CopyPlugin = require("copy-webpack-plugin");

plugins: [
new CopyPlugin({
patterns: [
{
from: 'vue/images', // src location
to: 'images', // destination location in dist folder
},
],
options: {
concurrency: 100,
},
}),
]

Then in my css I could just reference the image as relative from the dist folders css to the dist folder images folders:

background-image: url(../images/loading.svg);

Seems a bit odd to me that I had to do it this way in order not to get the extra svg file so if anyone comes up with a better solution or knows how not to create the extra file, please feel free to answer



Related Topics



Leave a reply



Submit