Handling assets with webpack within ReactJs application - reactjs

I need to load an image in my React component :
webpack.config.js
const path = require('path');
const webpack = require('webpack');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const CheckerPlugin = require('awesome-typescript-loader').CheckerPlugin;
const bundleOutputDir = './wwwroot/dist';
module.exports = (env) => {
const isDevBuild = !(env && env.prod);
return [{
stats: { modules: false },
entry: { 'main': './ClientApp/boot.tsx' },
resolve: { extensions: ['.js', '.jsx', '.ts', '.tsx'] },
output: {
path: path.join(__dirname, bundleOutputDir),
filename: '[name].js',
publicPath: 'dist/'
},
module: {
rules: [
{ test: /\.tsx?$/, include: /ClientApp/, use: 'awesome-typescript-loader?silent=true' },
{ test: /\.css$/, use: isDevBuild ? ['style-loader', 'css-loader'] : ExtractTextPlugin.extract({ use: 'css-loader?minimize' }) },
{ test: /\.(png|jpg|jpeg|gif|svg)$/, loader: 'file-loader' },
{ test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/, loader: "url-loader?limit=10000&mimetype=application/font-woff" },
{ test: /\.(ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/, loader: "file-loader" }
]
},
plugins: [
new CheckerPlugin(),
new webpack.DllReferencePlugin({
context: __dirname,
manifest: require('./wwwroot/dist/vendor-manifest.json')
})
].concat(isDevBuild ? [
// Plugins that apply in development builds only
new webpack.SourceMapDevToolPlugin({
filename: '[file].map', // Remove this line if you prefer inline source maps
moduleFilenameTemplate: path.relative(bundleOutputDir, '[resourcePath]') // Point sourcemap entries to the original file locations on disk
})
] : [
// Plugins that apply in production builds only
new webpack.optimize.UglifyJsPlugin(),
new ExtractTextPlugin('site.css')
])
}];
};
In the component, I tried to load the image like this :
import Logo from '../css/images/logo.png';
but it did not work !
How can I edit the configure the webpack to handle the assets espacially images?
Thanks,

From your example, I considering your image file is locally stored. Did you created reactjs app using created-react-app or ejected the app.
import Logo from '../css/images/logo.png'
and use like <img src={Logo} className="blue"/>
or <img src={require('../css/images/logo.png')} className="blue"/>

Related

React use css from imported files only

Hi guys I have an issue with my css in the react project
I have a component called header.jsx and the header.scss file is imported in it, so I want the css to be applied from header.scss only not from any other file (even though the className names are same).
There is a way to wrap around with a div and provide unique className,or use css-modules but can the same be done with webpack configuration ? I tried to change a bit but couldn't let it happen.
Below is my webpack config for the project
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
mode: "development",
plugins: [
new HtmlWebpackPlugin({ template: "./public/index.html" }),
new MiniCssExtractPlugin(),
],
output: {
path: path.join(__dirname, "/dist"),
filename: "index.bundle.js",
},
resolve: {
extensions: [".js", ".jsx"],
},
devServer: {
static: path.resolve(__dirname, "dist"),
port: 9000,
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /nodeModules/,
resolve: {
extensions: [".js", ".jsx"],
},
use: {
loader: "babel-loader",
},
},
{
test: /\.s[ac]ss$/i,
use: [
MiniCssExtractPlugin.loader,
{
loader: "css-loader",
options: {
modules: true,
},
},
"sass-loader",
],
},
],
},
};

Webpack Source Map Export Compiled JS

I was using webpack 3, there was no hot reload issue and then I upgraded to webpack 5.
Webpack version: ^5.50.0, React version: 17.0.2
Webpack source map doesn't work properly. I attached a picture of output at the bottom.
When I read webpack documentation, there is no difference between my config with offical config.
Here is my webpack hot config for development;
const webpack = require('webpack') //to access built-in plugins
const HtmlWebpackPlugin = require('html-webpack-plugin') //installed via npm
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
const CopyPlugin = require('copy-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const vendorArray = require('./vendors')
const path = require('path')
const Dotenv = require('dotenv-webpack')
module.exports = {
mode: 'development',
devtool: 'source-map',
entry: {
main: [
'react-hot-loader/patch',
'webpack-dev-server/client?http://0.0.0.0:3002',
'webpack/hot/only-dev-server',
'./src/main.js'
]
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].[hash:8].js'
},
resolve: {
extensions: ['.js', '.jsx', '.css', '.scss', '.json']
},
module: {
rules: [
{
test: /\.js?$/,
exclude: /(node_modules|bower_components)/,
loader: './config/webpack/style-loader'
},
{
test: /\.m?js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: [['#babel/preset-env', { targets: 'defaults' }], '#babel/preset-react'],
plugins: [
'#babel/plugin-transform-runtime',
'#babel/plugin-proposal-class-properties',
'#babel/plugin-proposal-optional-chaining',
'#babel/plugin-proposal-nullish-coalescing-operator',
[
'#babel/plugin-proposal-decorators',
{
legacy: true
}
]
]
}
}
},
{
test: /\.(sa|sc|c)ss$/,
use: [MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader', 'sass-loader']
},
{
test: /\.(eot|woff|woff2|ttf|svg|png|jpg|gif)([\?]?.*)$/,
type: 'asset/resource'
}
]
},
plugins: [
new webpack.DefinePlugin({
APP_ENV: JSON.stringify('dev')
}),
new HtmlWebpackPlugin({
template: './public/index.html',
templateParameters: {
recaptchaSiteKey: '6LfbRrEZAAAAAL1EiyUSq1yzEw1xqleak2xC2pzi',
intranetLogin: true
}
}),
new MiniCssExtractPlugin(),
new Dotenv({
path: path.resolve(__dirname, './../../.env.test')
})
]
}

Images not showing up in routing / react build vs Dev

Im trying to get my images to appear in my build version of my react code.
```import reportIcon from "../../../../../src/img/reportmanager.svg";
<img src={reportIcon } className="img-icons-list" />```
this code works when I am in build version. My reportmanager icon shows up, but when I navigate to www.mywebsite.com/reports/user -- the icon disappears
import reportIcon from "/src/img/reportmanager.svg";
does not work either. here is my webpack.config.js file
```const HtmlWebPackPlugin = require("html-webpack-plugin");
const ExtractTextPlugin = require("extract-text-webpack-plugin");
var path = require('path');
module.exports = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname + '/public'),
filename: 'bundle.js'
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
loader: 'babel-loader',
options: {
presets: ['#babel/preset-env',
'#babel/react', {
'plugins': ['#babel/plugin-proposal-class-properties']
}]
},
},
{
test: /\.css$/,
use: ExtractTextPlugin.extract({
fallback: "style-loader",
use: "css-loader"
})
},
{
test: /\.(eot|ttf|woff|woff2)$/,
loader: 'file-loader?name=./font/[name]_[hash:7].[ext]'
},
{
test: /\.(jpg|png|svg)$/,
loader: 'file-loader?name=./img/[name]_[hash:7].[ext]'
}
]
},
devServer: {
historyApiFallback: {
index: "/",
}
},
plugins: [
new ExtractTextPlugin("css/style.css"),
new HtmlWebPackPlugin({
template: "./src/index.html",
filename: "./index.html"
}),
function () {
this.plugin("done", function (stats) {
if (stats.compilation.errors && stats.compilation.errors.length && process.argv.indexOf('--watch') == -1) {
console.log(stats.compilation.errors);
process.exit(1); // or throw new Error('webpack build failed.');
}
// ...
});
}
]
};
I needed to put
<base href="/">
in the index.html of my react project.

Webpack running through grunt webpack doesn't error or complete, or do anything

Trying to convert an old system off bower into npm using webpack, and grunt webpack. Just trying to use webpack to load in NPM files, not run anything else, and the rest of the grunt file finishes loading and uglifying and stuff, and runs its own node server. It gets to this point and freezes and never comes back.
Loading "grunt-webpack" plugin
Registering "/Users/***/***/***/node_modules/grunt-webpack/tasks" tasks.
Loading "webpack-dev-server.js" tasks...OK
+ webpack-dev-server
Loading "webpack.js" tasks...OK
+ webpack
Running "webpack" task
Here's my grunt code (super basic obviously)
webpack: {
options: require("./config/webpack.dev.js"),
},
Here's that dev file
const webpack = require('webpack');
const helpers = require('./helpers');
const merge = require('webpack-merge');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { BaseHrefWebpackPlugin } = require('base-href-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const ConcatPlugin = require('webpack-concat-plugin');
const ngInventory = require('./ng1-vendor-index.js');
const common = require('./webpack.common.js');
const ENV = process.env.NODE_ENV = process.env.ENV = 'dev';
module.exports = merge(common(ENV), {
devtool: 'source-map',
module: {
rules: [
{
test: /\.(ts|js)$/,
loaders: ['angular-router-loader'],
},
{
test: /\.((s*)css)$/,
use: [{
loader: 'style-loader',
},{
loader: 'css-loader',
},{
loader: 'sass-loader',
}]
},
{
test: /src\/.+\.(ts|js)$/,
exclude: /(node_modules|\.spec\.ts$)/,
loader: 'istanbul-instrumenter-loader',
enforce: 'post',
options: {
esModules: true
}
}
]
},
debug: true,
devTool: 'eval',
plugins: [
new ConcatPlugin({
uglify: false,
sourceMap: true,
name: 'vendor',
outputPath: './',
fileName: '[name].[hash].js',
filesToConcat: ngInventory.vendor1
}),
new BaseHrefWebpackPlugin({ baseHref: '/'}),
new HtmlWebpackPlugin({
favicon: helpers.root('client/assets/image/favicon.png'),
template: "./client/index.html",
filename: "./client/index.html",
}),
new webpack.NoEmitOnErrorsPlugin(),
],
});
And here is the common file:
const path = require('path');
const webpack = require('webpack');
const nodeExternals = require('webpack-node-externals')
const helpers = require('./helpers');
module.exports = env => ({
entry: {
server: './server/app.js',
},
resolve: {
extensions: ['.ts', '.js']
},
output: {
path: helpers.root(`dist/${env}`),
publicPath: '/',
filename: '[name].js'
},
target: 'node',
node: {
// Need this when working with express, otherwise the build fails
__dirname: false, // if you don't put this is, __dirname
__filename: false, // and __filename return blank or /
},
externals: [nodeExternals()],
module: {
rules: [
{
// Transpiles ES6-8 into ES5
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
},
{
test: /\.html$/,
include: [
helpers.root('client'),
],
loader: 'html-loader'
},
{
test: /\.((s*)css)%/,
include: [
helpers.root('client/app'),
helpers.root('client/components'),
],
exclude: 'node_modules/',
loaders: ['to-string-loader', 'css-loader', 'sass-loader']
},
{
test: /\.(woff|woff2|eot|tts)$/,
use: [{
loader: 'file-loader'
}]
}
]
},
plugins: [
new webpack.DefinePlugin({
'process.env': {
'ENV': JSON.stringify(env)
}
}),
new webpack.ContextReplacementPlugin(/\#angular(\\|\/)core(\\|\/)esm5/, path.join(__dirname, './client')),
]
});
A sample from the vendor index file:
const helper = require('./helpers');
exports.vendor1 = [
helper.root('node_modules/lodash/lodash.js'),
helper.root('node_modules/lodash-deep/lodash-deep.js'),
...
...
]
I'm just really not sure what to do, couldn't bring up any google results or stack results because theres no errors happening either. I've tried all verbose levels of logging all to no avail. What in the world am I missing?
As the documentation shows, you haven't configured any targets, like dev or prod. You've only specified options. You want
webpack: {
options: {},
dev: require("./config/webpack.dev.js"),
},
As an aside, there's no benefit to using Webpack with Grunt.

Images are loaded in external library, how to load them with webpack?

first and foremost I need to say that I know little of fundamentals of Webpack, and this is probably why I can't find a solution.
So I know in order to load images I need to require a path instead of just typing it as a string require('path/to/image')
Then I got an external library where I need to pass a path property, where lay multiple images. It doesn't seem to work, so how can I load them into my website?
<CountrySelect
multi={false}
flagImagePath="../../../public/flags/" //folder with multiple images
/>
Webpack config:
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const outputDirectory = 'dist';
module.exports = {
entry: './src/client/index.js',
output: {
path: path.join(__dirname, outputDirectory),
filename: 'bundle.js',
publicPath: '/',
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader'
}
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
},
{
test: /\.(png|woff|woff2|eot|ttf|svg|jpg|jpeg)$/,
loader: 'url-loader?limit=100000'
}
]
},
devServer: {
historyApiFallback: true,
port: 3000,
open: true,
proxy: {
'/api': 'http://localhost:8080'
}
},
plugins: [
new CleanWebpackPlugin([outputDirectory]),
new HtmlWebpackPlugin({
template: './public/index.html',
favicon: './public/favicon.ico'
})
]
};
image-webpack-loader - automatically reduces/compress the bigger image.
url-loader - if image size is small it will included as part of bundle.js otherwise separate directory is created and images are placed inside of it.
npm install --save-dev image-webpack-loader url-loader file-loader
webpack.config.js
const config = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'build'),
filename: 'bundle.js',
publicPath: 'build/' //This is important to load your images.
},
module: {
rules: [
{
test: /\.js$/,
use: [
{ loader: 'babel-loader' },
]
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader'],
},
{
test: /\.(gif|png|jpe?g|svg)$/i,
use: [
{
loader: 'url-loader',
options: { limit: 40000 } //if image of size lessthan 40kb include it in bundle.js
},
'image-webpack-loader'
]
}
]
}
}
Sample Code.
import big from '../images/big.jpg';
import small from '../images/small.png';
const image = document.createElement('img');
image.src = small;
document.body.appendChild(image);
const bigimage = document.createElement('img');
bigimage.src = big;
document.body.appendChild(bigimage);
you can learn more about webpack from Handling Images with Webpack.
I solved the problem by using CopyWebpackPlugin.
plugins: [
new CleanWebpackPlugin([outputDirectory]),
new HtmlWebpackPlugin({
template: './public/index.html',
favicon: './public/favicon.png'
}),
new CopyWebpackPlugin([{ from: './public/flags', to: 'flags', toType: 'dir'
}]),
]
and in CountrySelect:
flagImagePath="/flags/"
So that in the time of production, where static directory is dist, flags are derived from dist directory.

Resources