Webpack 5 images not found when importing to a module - reactjs

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.

Related

Webpack build for exisitng AngularJS project

I am looking to migrate the existing Ruby based build system in our AngularJS(1.4.X) project to Webpack. The project code is not using JS modules and being with old-school Angular code patter I am not sure how Webpack will find all the controller and factory files in the project.
Folder structure is like,
-app
- assets
- javascripts
- ctrl
- controllerA.js
- controllerB.js
-services
-serviceA.js
-serviceB.js
- angular.min.js
- angular-route.js
- main.js
Wen I use the main.js in my entry point it get copied into the build folder but none of the other files as processed by Webpack even if I use babel-loader to .js rule.
One option I can think of is to use all other files into a separate bundle file using something like
https://www.npmjs.com/package/webpack-merge-and-include-globally, but I want to know whether there is a better way of doing it.
My current webpack config is as below.
module.exports = {
context: __dirname +'/app',
entry: {
'app-portal': [
'/assets/javascripts/main.js',
'/assets/javascripts/angular.min.js',
'/assets/stylesheets/portal/style.css',
'/assets/stylesheets/portal/navbar.css',
'/assets/stylesheets/portal/animation.css',
'/assets/stylesheets/portal/bootstrap.min.css',
'/assets/stylesheets/portal/bootstrap-notify.css',
'/assets/stylesheets/portal/fontello.css',
]
},
output: {
path: __dirname + "/dist/assets",
},
module: {
rules: [
{
test: /\.js$/,
exclude: /(node_modules)/,
use: {
loader: 'babel-loader',
},
},
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
{
loader:'css-loader',
options: {
sourceMap: true,
url: false,
},
},
],
},
plugins: [
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
template: './views/portal/index.html',
filename: '../index.html',
}),
new MiniCssExtractPlugin({
filename: './[name].css',
linkType: false,
ignoreOrder: false,
}),
new CopyPlugin({
patterns: [
{
from: './views/portal/**/*.*',
to: "../[name].[ext]",
globOptions: {
ignore: [
'**/index.*',
],
},
},
{
from: './assets/fonts/*.*',
to: "./[name].[ext]",
},
{
from: './assets/images/portal/*.*',
to: "./[name].[ext]",
},
{
from: './assets/theme/*.*',
to: "./[name].[ext]",
}
]
}),
],
Probably Webpack is not the right solution for me as I don;t want to change the source code as suggested in Webpack plugins and/or strategies for AngularJS
You can try something like this (we use it for running tests):
bundle.js:
const jsConext= require.context('.', true, /\.js/);
ng1Context.keys().forEach(ng1Context);
const cssConext= require.context('.', true, /\.css/);
ng1Context.keys().forEach(ng1Context);
...
entry: { 'app-portal': 'bundle.js' }
This should work in general (You might need fix order for css or in case of multiple angular modules etc.)

React.js gif is not loading

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')

How to make React to ignore some folder files updates and don't recompile?

I've got problem - on some requests backend creates static html files in frontend subfolder which causes React to recompile and reload page. This is bad for me.
If simplify, I've got following project directory structure:
backend/
...
frontend/
node_modules/
package.json
package-lock.json
public/
statements/
...
src/
webpack.config.js
...
...
I want React to ignore public/statements folder updates.
How could I make it?
Found that maybe I should configure Webpack exlude rule, but I failed to do it.
UPD1: Here is my webpack.config.js:
module.exports = {
module: {
rules: [
{
loader: 'babel-loader',
test: /\.jsx?$/,
exclude: /public/
}
]
}
};
UPD2: Tried also this one, same trouble:
const path = require('path');
module.exports = {
devServer: {
watchOptions: {
ignored: [
path.resolve(__dirname, 'public', 'statements'),
]
}
}
};
in the webpack.config.js file set the rules property array and set exclude folder
like this
module: {
rules: [{
loader: 'babel-loader',
test: /\.js$/,
exclude: /public/statements/
}
For HMR reloading?
devServer: {
watchOptions: {
ignored: [
path.resolve(__dirname, 'public', 'statements'),
]
}
}

Why i get hashed .jpeg file when running 'npm run build' with webpack

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.

How to include node_modules using webpack?

In my angularJs 1.3 application, earlier I was using bower and grunt and it was working fine. I was adding files in my index.html like the following screenshot. But now I have installed all the packages using NPM and using WEbPack 4.21.0 for bundling and run the application. But now if I remove the packages link from Index.html file my application stops working. But I don't want all those links in Index.html and just want to generate a bundle file from those files. Kindly guide me how can I achieve this? Currently, its just adding angular.js file and few other files in vendor.js.
Index.html
Package.json
webpack.config.js
Updated Question:
Now i am using following webpack.config.js but its creating bootstrap_and_some_plugin.css.js . It has to create css file but don't know why it's creating js file?
module.exports = {
context: __dirname + '/app/scripts',
resolve: {
modules: ['bower_components', 'node_modules'],
alias: {
bower_components: __dirname + '/app/bower_components',
assets: __dirname + '/app/assets'
},
extensions: ['.js', '.jsx', '.css']
},
module: {
rules: [
{
test: /\.css$/,
use: [
{ loader: "style-loader" },
{ loader: "css-loader" }
]
},
{
test: /\.(woff(2)?|ttf|eot|svg)(\?v=\d+\.\d+\.\d+)?$/,
use: [{
loader: 'file-loader',
options: {
name: '[name].[ext]',
outputPath: 'fonts/'
}
}]
}
]
},
entry: {
app: './main-app.js',
'bootstrap_and_some_plugin.css': [
'bower_components/font-awesome/css/font-awesome.css',
'bower_components/seiyria-bootstrap-slider/dist/css/bootstrap-slider.min.css',
'bower_components/angular-ui-tree/dist/angular-ui-tree.min.css',
]
},
output: {
filename: '[name].js',
path: __dirname + '/app/scripts',
//chunkFilename: '[id].[chunkhash].js',
},
devServer: {
contentBase: './app',
host: 'localhost',
port: '9000',
inline: true,
compress: true,
proxy: {
'/api/**': {
//target: 'http://10.189.1.159:8080',
target: 'http://localhost:9100',
secure: false,
changeOrigin: true,
cookieDomainRewrite: true
}
},
open: true
},
plugins: [
]
};
In the file webpack.config.js, you add this property inside the resolve property:
resolve: {
alias: {
bower_components: __dirname + '/app/bower_components'
}
}
In the file main-app.js, if you want to use some js file, you call like this:
require('bower_components/jquery/dist/jquery.js');
require('bower_components/angular/angular.js');
require('bower_components/bootstrap/dist/js/bootstrap.js');
// ...
You need to specify the path of the file webpack.config.js. In my example, all the path looks like:
your_project
webpack.config.js
app
bower_components
jquery
...
angular
...
bootstrap
...
__dirname refers to the current path of the js file which is using it. If you use __dirname inside the webpack.config.js file, it will render your_project. Or using it inside jquery.js, it will render your_project\app\bowser_components\jquery\dist.
Then, build to bundle.js file and delete all the path in the Index.cshtml file.
Hope this helps!
UPDATE: If your js target file goes too big. You can split modules to multiple parts, like this:
entry: {
'bootstrap_and_some_plugin.css': [
'./app/bower_components/bootstrap/dist/css/bootstrap.min.css',
'./app/bower_components/some-plugin/css/some-plugin.css'
],
'jquery_and_angular.js': [
'./app/bower_components/jquery/dist/jquery.js',
'./app/bower_components/angular/angular.js'
],
'site.js': ['./js/site']
}
Then, in your Index.cshtml:
<link href="bootstrap_and_some_plugin.css" rel="stylesheet" />
<!-- body content -->
<script src="jquery_and_angular.js"></script>
<script src="site.js"></script>
UPDATE 2: You need to install the 2 packages babili-webpack-plugin and extract-text-webpack-plugin
In the file webpack.config.js:
// define these variables before "module.exports"
var BabiliPlugin = require('babili-webpack-plugin');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
module.exports = {...};
Then, setting the pluggin options:
plugins: [
new BabiliPlugin({}, { test: /\.js$/, comments: false }),
new ExtractTextPlugin('[name]'),
... and other options
]
and the output options:
output: {
filename: '[name]',
... and other options
}

Resources