I am trying to load a local image in a simple React application with Webpack. I load the image as:
const DogImage = require('../../public/dog.jpg');
const Image = () => {
...
<img src={DogImage} width="100px"/>
}
My webpack config includes the following:
output: {
filename: 'widget.js',
path: path.resolve(bundleOutputDir),
publicPath: '/public/'
},
devServer: {
contentBase: bundleOutputDir,
publicPath: '/public/'
},
...
{
test: /\.(png|jpe?g|gif)$/i,
use: [
{
loader: 'file-loader',
},
],
},
When I build the app, I get the image file named 8ce03579ff1756938e787945c032a0a3.jpg in my dist folder and when I console.log the image I get:
It shows up on the screen with the HTML missing file icon. The image is definitely in the correct path because I can't build if the path doesn't match the image.
Please let me know if you have any ideas or if I can provide more info! Thanks
Related
I have a very simple Webpack 5 config, and I am trying to import images for use in my React app. I am able to import the image and use it without Webpack complaining:
import SomeImage from 'assets/some-image-jpg'
...
<img src={SomeImage} />
However, the image is not found in the browser. I am using webpack-manifest-plugin and the devServer option writeToDisk to serve the assets via Django. The JS and CSS work as expected.
const path = require('path');
const { WebpackManifestPlugin } = require('webpack-manifest-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
entry: './front/index.js',
output: {
filename: 'index-bundle.js',
path: path.resolve(__dirname, './local-static'),
publicPath: '/',
assetModuleFilename: 'img/[hash][ext][query]',
},
devServer: {
writeToDisk: true,
disableHostCheck: true,
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
loader: "babel-loader",
},
{
test: /\.(scss|css)$/,
use: [MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader'],
},
{
test: /\.(png|svg|jpg|jpeg|gif)$/i,
type: 'asset/resource',
},
]
},
resolve: {
modules: [
path.join(__dirname, "front"),
"node_modules"
]
},
plugins: [
new MiniCssExtractPlugin({ filename: 'css/[name].css' }),
new WebpackManifestPlugin({ publicPath: './' }),
],
};
EDIT: Sample output of mainfest.json file:
{
"main.css": "./css/main.css",
"main.js": "./index-bundle.js",
"main.jpg": "./img/fbf8476a272a27c10e80.jpg",
"front/assets/no-image.jpg": "./img/fbf8476a272a27c10e80.jpg"
}
"front" is the name of the folder where the source files are stored.
EDIT 2: Contents of output folder:
├── css
│ └── main.css
├── img
│ └── fbf8476a272a27c10e80.jpg
├── index-bundle.js
└── manifest.json
Your image appears to exist, only it has been renamed with the with a hash key prefix. This is to get around image cache issues when the file name doesn't change, but the image has. Normally the plugin is smart enough to fix most but NOT all of the references to the rename.
To check whether your image file is actually being written to disk you can temporarily alter the assetModuleFilename key to use the original name and file extension as shown in the section below. If your image file is unlikely to change you can probably make this change permanent.
You should now hopefully see the file in the browser!
Otherwise workaround by manually replacing the new hashed name of the image referenced in your config or other files where necessary. A map file manifest.json of all hash entries can be generated by the plugin automatically
example:
output: {
publicPath:"", // default is "auto"
path: path.join(__dirname, "build"),
filename: "[name].bundle.js",
clean: true,
assetModuleFilename: '[name][ext]'
},
Warning!
Do not put a period mark(.) between the substitutions in the assetModuleFilename key as is done in the filename key or you may get a file not found error.
I have a common use case to load a spinner in the component. This is my folder structure.
src
/components
/table
-Table.js
-Spinner.js
I import spinner like this
const spinner = require('./spinner.gif');
When I console log spinner I got this
And call that in the component like this
<img src={spinner} alt='Data is loading...' />
But gif image is not loading. Instead I am getting the alt text.
How do I fix this with React?
My answer follows the documentation on webpack
In your folder add a package for image loader
npm install --save-dev file-loader
Then change your webpack.config.js or any other named config file as below.
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist'),
},
module: {
rules: [
{
test: /\.css$/,
use: [
'style-loader',
'css-loader'
],
},
// Added below -----------
{
test: /\.(png|svg|jpg|gif)$/,
use: [
'file-loader',
],
},
// Added above ---------------
],
},
};
Then you can import images as usual by doing
import image from './image.gif';
Or
const image = require('./image.gif')
I am building a simple React app from scratch using Webpack.
I was finally able to run the dev server and when I tried to apply some styles via CSS, the files wouldn't load and I assume my Webpack 4 configuration is not right.
Here is the code:
webpack.config.js
// const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const path = require('path');
module.exports = {
mode: 'development',
entry: ['./src/index.js'],
resolve: {
extensions: [".js", ".jsx"]
},
output: {
filename: 'main.js',
path: path.resolve(__dirname, 'dist'),
publicPath: '/dist',
},
devServer: {
contentBase: path.join(__dirname, 'dist'),
compress: true,
port: 8080
},
module: {
rules: [
{
test: /\.js|.jsx$/,
exclude: /node_modules/,
loader: "babel-loader",
options: {
presets: ["react"]
}
},
{
test: /\.css$/,
use: ["style-loader", "css-loader"]
},
{
test: /\.(png|jpg)$/,
loader: 'url-loader'
}
]
},
};
My project structure is like this, I will include only src because it lives in the root:
**src**
|_assets
|_componentns
|_styles
|_App.css
|_index.css
App.jsx
index.js
index.html
I would like to be able to add multiple css files for each component I have and apply them, and to be able to style the index the index.html.
Thank you very much for your help.
Your webpack configuration looks fine.
make sure you import the required css files in your components.
import "./App.css";
class App extends Component {
render() {
return (
<div>
<Child />
</div>
);
}
}
All you have to do is import the CSS files when needed as you would a JavaScript module. So if you want to have a style sheet for your whole application, you can import a global stylesheet in your index.js.
import './styles/index.css';
and you can do the same for each component with specific styles
import './styles/App.css'
in which case you might want to setup CSS modules to avoid overlapping class names.
Ok, rookie mistake here, the way I ahve set up webpack is I have to build it first and then run the dev server, no the other way around.
All answers above are valid and helpful, I just forgot to run build after changes.
Im a new beginner on develop react app.
Im trying to figure out how to set up my webpack.config.js file.
I have following ended up with this structure as you can see on the picture link below.
My question is: When im running 'npm run build' , its hashing the picture and put it into the /dist folder. How can i configure so it does not?
Because im using copyWebpackPlugin() to copy my images and push it to the dist folder, but i dont want the picture which i marked with arrow.
If anyone have some advice just bring it on.
This is how my webpack.config.js file look like:
const path = require("path");
const webpack = require("webpack");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const CleanWebpackPlugin = require("clean-webpack-plugin");
const CopyWebpackPlugin = require("copy-webpack-plugin");
module.exports = {
entry: "./src/index.js",
mode: "development",
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /(node_modules|bower_components)/,
loader: "babel-loader"
},
{
test: /\.s?css$/,
loader: ["style-loader", "css-loader"]
},
{
test: /\.(jpe?g|png|gif|woff|woff2|eot|ttf|svg)(\?[a-z0-9=.]+)?$/,
loader: "url-loader?limit=100000"
}
]
},
resolve: { extensions: [".js", ".jsx"] },
output: {
path: path.resolve(__dirname, "dist/"),
filename: "bundle.js"
},
devtool: "cheap-module-eval-source-map",
devServer: {
contentBase: path.join(__dirname, "public/"),
proxy: {
"/api/*": {
target: "http://localhost:3000/",
secure: "true"
}
},
port: 4000,
publicPath: "http://localhost:4000/dist/",
hotOnly: true,
historyApiFallback: true
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new CleanWebpackPlugin(["dist"]),
new HtmlWebpackPlugin({
filename: "index.html",
template: "./public/index.html"
}),
new CopyWebpackPlugin([{ from: "public/images", to: "images" }])
]
};
I would suggest instead of copy-webpack-plugin use file-loader to copy images
{
test: /\.(png|jpg|gif|jpeg)$/,
use: [{
loader: 'file-loader',
options: {
name: 'images/[name].[ext]',
}
}]
}
if you want hash instead of name
name: 'images/[hash].[ext]',
Package
npm install --save-dev file-loader
It is because the url-loader has a default fallback to file-loader. So if your image is bigger than the limit you have set for url-loader, it does not rewrite the image to base64 data:image in your css, instead gives it to file-loader and it copies that image to your dist folder (output path).
So if you do not want this, disable the fallback option for url-loader
But I also think you should have configure your webpack to copy the files with file-loader properly instead that copy plugin. But you know...
I would give you an example based on your config but I am currently on mobile so I can't code right now.
My team moved all the images of company website into a CDN. (https://cdn.irobo.co.kr/images)
However, I'd like to use those images without changing current code base, which has a lot of: (reactjs code)
<image src={require('img/common/logo.jpg')} />
here's the webpack config for the website:
{
module: {
loaders:[{
test: /\.(png|jpg)$/,
loader: 'file-loader?name=[name].[ext]',
}],
}
...
resolve: {
alias: {
img: path.join(srcPath, 'app/img'),
}
}
}
Here's what I tried:
...
resolve: {
alias: {
img: 'https://cdn.irobo.co.kr/images',
}
}
}
Bundling assets from external urls with Webpack
The url-loader plugin for webpack gives you the ability to take use assets from external url by encoding them in base64.
The url loader works like the file loader, but can return a Data Url
if the file is smaller than a byte limit.
The limit can be specified with a query parameter. (Defaults to no
limit)
Remember to install the url-loader plugin as a project dependency.
npm install --save-dev url-loader
Configure the url-loader plugin
Here is a sample webpack config to set up the url-loader plugin.
webpack.config.js
module.exports = {
entry: './main.js',
output: {
path: './build', // This is where the images and js will go
publicPath: 'http://mycdn.com/', // used to generate URLs to e.g. images
filename: 'bundle.js'
},
module: {
loaders: [
// use ! to chain loaders
{ test: /\.less$/, loader: 'style-loader!css-loader!less-loader' },
{ test: /\.css$/, loader: 'style-loader!css-loader' },
// inline base64 URLs for <=8k images, direct URLs for the rest
{ test: /\.(png|jpg)$/, loader: 'url-loader?limit=8192' }
]
}
};
Import the assets in your app
app.jsx
import image from '../build/image.jpg';
<img src={image} />