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

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.

Related

webpack Can't resolve '../../assets/icon-font/icomoon.eot?e3uwku' in 'D:\sudi\aa-Server-side-render\MAPS101_Fresh_ssr\src\scss'

I want to implement SSR in an already build react application.
I am trying to include icon-fonts and ignore CSS files from node_modules of a particular library
Please help me, I am stuck here!!
I'm trying to load a font in my SCSS file but giving the below error.
my folder structure is :
my webpack.config.js is:
const path = require('path');
const HTMLWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
module.exports = {
// webpack optimization mode
mode: ('development' === process.env.NODE_ENV ? 'development' : 'production'),
// entry files
entry: 'development' === process.env.NODE_ENV ? [
'./src/index.js', // in development
] : [
'./src/index.js', // in production
],
// output files and chunks
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'build/[name].js',
},
// module/loaders configuration
module: {
rules: [
{
test: /\.(js|jsx)$/,
use: {
loader: 'babel-loader',
options: {
presets: ['#babel/preset-env', '#babel/preset-react']
}
},
exclude: [/node_modules/, /static/]
},
{
test: /\.(sa|sc|c)ss$/,
use: [
true ? 'style-loader' : MiniCssExtractPlugin.loader,
'css-loader',
'postcss-loader',
'sass-loader',
],
exclude: [/node_modules/, /static/]
},
{
test: /\.(css)$/,
use: [{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: '/public/css'
}
}, 'css-loader'],
exclude: [/node_modules/, /static/]
},
{
test: /\.(jpg|jpeg|png|svg|gif)$/,
use: [{
loader: 'file-loader',
options: {
name: '[md5:hash:hex].[ext]',
publicPath: '/public/img',
outputPath: 'img'
}
}]
},
{
test: /\.woff(\?v=\d+\.\d+\.\d+)?$/,
use: 'url-loader?limit=10000&mimetype=application/font-woff',
},
{
test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/,
use: 'url-loader?limit=10000&mimetype=application/font-woff',
},
{
test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/,
use: 'url-loader?limit=10000&mimetype=application/octet-stream',
},
{
test: /\.otf(\?v=\d+\.\d+\.\d+)?$/,
use: 'url-loader?limit=10000&mimetype=application/octet-stream',
},
{
test: /\.eot(\?v=\d+\.\d+\.\d+)?$/,
use: 'url-loader?limit=10000&mimetype=application/vnd.ms-fontobject',
},
]
},
// webpack plugins
plugins: [
// extract css to external stylesheet file
new MiniCssExtractPlugin({
filename: 'build/styles.css'
}),
// prepare HTML file with assets
new HTMLWebpackPlugin({
filename: 'index.html',
template: path.resolve(__dirname, 'src/index.html'),
minify: false,
}),
// copy static files from `src` to `dist`
new CopyWebpackPlugin({
patterns: [
{
from: path.resolve(__dirname, 'src/assets'),
to: path.resolve(__dirname, 'dist/assets')
}
]
}),
],
// resolve files configuration
resolve: {
// file extensions
extensions: ['.js', '.jsx', '.css', '.scss'],
},
// webpack optimizations
optimization: {
splitChunks: {
cacheGroups: {
default: false,
vendors: false,
vendor: {
chunks: 'all', // both : consider sync + async chunks for evaluation
name: 'vendor', // name of chunk file
test: /node_modules/, // test regular expression
}
}
}
},
// development server configuration
devServer: {
port: 8088,
historyApiFallback: true,
}, // generate source map
devtool: 'source-map' };
For me, I had the icomoon font in fonts directory. Did some investigation and found that the .scss file was trying to link it like this
url("./assets/styles/fonts/icomoon.svg?y2smka#icomoon"). The problem with that is icomoon.svg?y2smka#icomoon does not exist. So I looked in the fonts directory and found that it's called icomoon.eot
Solution:
In your _fonts.scss file, change all url("./assets/styles/fonts/icomoon.svg?y2smka#icomoon"). to url("./icomoon.eot")

How to import SASS file in React Webpack relative to project's root directory

I want to be able to import a SASS file in a React component relative to the project's root directory, as opposed to having to do it relative to the component.
I want to be able to do the following in the componenet:
import styles from "styles/popup.sass"
as opposed to
import styles from "../../styles/popup.sass"
I used the resolve options in order to be able to do this and it works for other file types (i.e. .js and .png), but it does not work for .sass files. I get the following error:
Cannot find module 'styles/popup.sass'
I'm not sure why this isn't working for SASS files and would really appreciate any help.
Project Structure:
src
- js
- popup
- greeting_componenet.jsx
- styles
- popus.sass
Webpack Config file
var webpack = require("webpack"),
path = require("path"),
fileSystem = require("fs"),
env = require("./utils/env"),
CleanWebpackPlugin = require("clean-webpack-plugin").CleanWebpackPlugin,
CopyWebpackPlugin = require("copy-webpack-plugin"),
HtmlWebpackPlugin = require("html-webpack-plugin"),
WriteFilePlugin = require("write-file-webpack-plugin");
// load the secrets
var alias = {};
var secretsPath = path.join(__dirname, ("secrets." + env.NODE_ENV + ".js"));
var fileExtensions = ["jpg", "jpeg", "png", "gif", "eot", "otf", "svg", "ttf", "woff", "woff2"];
if (fileSystem.existsSync(secretsPath)) {
alias["secrets"] = secretsPath;
}
var options = {
mode: process.env.NODE_ENV || "development",
entry: {
popup: path.join(__dirname, "src", "js", "popup.js"),
options: path.join(__dirname, "src", "js", "options.js"),
background: path.join(__dirname, "src", "js", "background.js")
},
output: {
path: path.join(__dirname, "build"),
filename: "[name].bundle.js"
},
module: {
rules: [
{
test: /\.css$/,
loader: "style-loader!css-loader",
include: [
path.join(__dirname, 'src'),
/node_modules\/(semantic-ui-css)/
],
},
{
test: /\.(scss|sass)$/i,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
importLoaders: 1,
modules: {
localIdentName: "[path]___[name]__[local]___[hash:base64:5]",
},
}
},
{
loader: 'postcss-loader',
options: {
plugins: function() {
return [require('autoprefixer')]
}
}
},
'sass-loader'
],
exclude: /node_modules/
},
{
test: new RegExp('\.(' + fileExtensions.join('|') + ')$'),
loader: "file-loader?name=[name].[ext]",
include: [
path.join(__dirname, 'src'),
/node_modules\/(semantic-ui-css)/
],
},
{
test: /\.html$/,
loader: "html-loader",
exclude: /node_modules/
},
{
test: /\.(js|jsx)$/,
loader: "babel-loader",
exclude: /node_modules/
}
]
},
resolve: {
alias: alias,
extensions: fileExtensions.map(extension => ("." + extension)).concat([".jsx", ".js", ".css", ".sass"]),
modules: [
path.resolve(__dirname, 'src'),
'node_modules'
]
},
plugins: [
// clean the build folder
new CleanWebpackPlugin(),
// expose and write the allowed env vars on the compiled bundle
new webpack.EnvironmentPlugin(["NODE_ENV"]),
new CopyWebpackPlugin([{
from: "src/manifest.json",
transform: function (content, path) {
// generates the manifest file using the package.json informations
return Buffer.from(JSON.stringify({
description: process.env.npm_package_description,
version: process.env.npm_package_version,
...JSON.parse(content.toString())
}))
}
}]),
new HtmlWebpackPlugin({
template: path.join(__dirname, "src", "popup.html"),
filename: "popup.html",
chunks: ["popup"]
}),
new HtmlWebpackPlugin({
template: path.join(__dirname, "src", "options.html"),
filename: "options.html",
chunks: ["options"]
}),
new HtmlWebpackPlugin({
template: path.join(__dirname, "src", "background.html"),
filename: "background.html",
chunks: ["background"]
}),
new WriteFilePlugin()
]
};
if (env.NODE_ENV === "development") {
options.devtool = "cheap-module-eval-source-map";
}
module.exports = options;
You need to add aliases for styles.
Something like:
module.exports = {
//...
resolve: {
alias: {
styles: path.resolve(__dirname, 'src/styles/'),
js: path.resolve(__dirname, 'src/js/')
}
}
};

Adding TypeScript to exsisting React Project (Not create-react-app)

I have been looking everywhere for a place to tell me how to add tsx compilers to an existing react project. This was not a create-react-app. Is it possible to use both TSX and JSX files in the same project? I don't want to do everything in TSX, but I definitely want to get some practice in and don't want to convert the whole thing. Do you guys have any places I can go look for this? Here is my webpack.config for reference (if you know a way I can add lmk)
Version: "react": "^16.8.1",
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin')
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
devtool: 'inline-source-map',
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html',
filename: "./index.html"
}),
new MiniCssExtractPlugin({
// Options similar to the same options in webpackOptions.output
// both options are optional
filename: "/static/cs/styles.css",
chunkFilename: "styles.css"
})
],
entry: './src/index.js',
output: {
path: path.join(__dirname, 'build'),
filename: 'static/js/bundle.js'
},
module: {
rules: [
{
test: /\.s?css$/,
use: [
"style-loader",
MiniCssExtractPlugin.loader,
"css-loader",
"sass-loader"
]
},
{
use: { loader: 'babel-loader' },
test: /\.js$/,
exclude: /node_modules/
},
{
test: /\.(png|svg|jpg|gif)$/,
use: [
{
loader: 'file-loader',
options: {
outputPath: '',
},
}
]
},
]
},
devServer: {
contentBase: path.join(__dirname, 'build'),
},
}

webpack4 hot reloading not working for some files

I have a problem with react webpack4 when i try to hot reload the changes fom certain files. And those files where the ones i modified from its original path (/from /src/containers to /src/components)
Rest of files reloading working well...
Code of my webpack config file is below:
const path = require('path');
const HtmlWebPackPlugin = require("html-webpack-plugin");
const Dotenv = require('dotenv-webpack');
const htmlWebpackPlugin = new HtmlWebPackPlugin({
template: "./src/index.html",
filename: "./index.html"
});
module.exports = {
output: {
path: path.join(__dirname, './'),
publicPath: '/'
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
},
{
test: /\.html$/,
use: [
{
loader: "html-loader",
options: { minimize: true }
}
]
},
{
test: /\.css$/,
use: [
{
loader: "style-loader"
},
{
loader: "css-loader",
options: {
modules: true,
importLoaders: 1,
localIdentName: "[name]_[local]_[hash:base64]",
sourceMap: true,
minimize: true
}
}
]
}
]
},
plugins: [
new HtmlWebPackPlugin({
template: "./src/index.html",
filename: "./index.html"
}),
new Dotenv()
],
devServer: {
historyApiFallback: true,
}
};
If you can share the error log, I may tell what is the real problem. But current config is missing for an entry point. If your application is a single page app, do it like the following code;
module.exports = {
entry: path.join(__dirname, "src", "index.js"),
...
}
if you are building multi page application do it like the following code;
module.exports = {
entry: {
pageOne: path.join(__dirname, "src", "pageOne", "index.js"),
pageTwo: path.join(__dirname, "src", "pageTwo", "index.js"),
pageThree: path.join(__dirname, "src", "pageThree", "index.js")
}
...
}
For anyone arriving here and having this issue, I had this exact problem where files in my 'src/components' directory weren't hot reloading.
I was able to fix it when I saw in the log that webpack was looking for the directory 'src/Components' for some reason, so I changed the name of the components directory to something totally different like 'placeholder' then changed it back to 'components' and ran a fresh install.

React app looking for bundle.js in component folder not project root

The errors I get below are shown in the console after I refresh on a nested route (register/email-confirmation). Whereas non-nested routes do not get this error.
I think the main problem is that it's searching for bundle.js and the image in the nested route path, as opposed to the root path.
The errors in my console:
GET http://localhost:3002/register/bundle.js net::ERR_ABORTED
Refused to execute script from 'http://localhost:3002/register/bundle.js' because its MIME type ('text/html') is not executable, and strict MIME type checking is enabled.
GET http://localhost:3002/register/a5e694be93a1c3d22b85658bdc30008b.png 404 (Not Found)
My webpack.config.js:
const webpack = require('webpack');
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const BUILD_PATH = path.resolve( __dirname, "./client/build" );
const SOURCE_PATH = path.resolve( __dirname, "./client/src" );
const PUBLIC_PATH = "/";
...
module.exports = {
devtool: 'eval-source-map',
context: SOURCE_PATH,
entry: ['babel-polyfill', SOURCE_PATH + '/index.jsx'],
module: {
rules: [
{
test: /\.jsx?$/,
exclude: [/node_modules/, /server/],
use: {
loader: 'babel-loader',
options: {
presets: ['env', 'es2015', 'react', 'stage-1', 'stage-0', 'stage-2'],
plugins: [
'transform-decorators-legacy',
'transform-es2015-destructuring',
'transform-es2015-parameters',
'transform-object-rest-spread'
]
}
}
},
{
test: /\.scss$/,
use: [{
loader: "style-loader"
}, {
loader: "css-loader"
}, {
loader: "sass-loader"
}]
},
{
test: /\.(png|jpg|gif)$/,
use: [
{
loader: 'file-loader',
options: {}
}
]
},
],
},
output: {
path: BUILD_PATH,
filename: "bundle.js",
},
devServer: {
compress: true,
port: 3002,
historyApiFallback: true,
contentBase: BUILD_PATH,
publicPath: PUBLIC_PATH,
},
plugins: [
new webpack.DefinePlugin(appConstants),
new HtmlWebpackPlugin({
filename: 'index.html',
template: path.resolve(__dirname, 'client/src/index.html'),
inject: true
}),
],
watch: true,
}
I don't know about this bug, but I highly recommend using fuse-box
fuse-box is the future of the build systems, within few minutes you will be running your project with high speed hot reload and many others utitilites...
check this react example seed, it's incredibly amazing..

Resources