Resolve fonts from ui components with react + webpack 5 - reactjs

I am creating a library with UI components to share among my react projects. Components are created with React and with Webpack 5. This is the webpack config file:
const path = require('path');
const webpack = require('webpack');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
entry: './src/index.js',
mode: 'production',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'index.js',
libraryTarget: 'umd',
library: 'ui-lib',
},
module: {
rules: [
{
test: /\.jsx?$/,
exclude: /node_modules/,
use: ['babel-loader'],
},
{
test: /\.(png|jpg|gif|svg)$/,
type: 'asset/resource',
},
{
test: /.(ttf|otf|eot|woff(2)?)(\?[a-z0-9]+)?$/,
type: 'asset/resource',
generator: {
filename: '[name][ext]',
},
},
{
test: /\.s[ac]ss$/i,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
modules: true,
sourceMap: false,
},
},
{
loader: 'resolve-url-loader',
options: { sourceMap: true, root: path.resolve(__dirname, 'src') },
},
{
loader: 'sass-loader',
options: {
sourceMap: true,
},
},
],
},
],
},
plugins: [
new MiniCssExtractPlugin({
filename: '[name].[hash].css',
chunkFilename: '[id].[hash].css',
}),
new webpack.ProvidePlugin({
React: 'react',
}),
],
resolve: {
extensions: ['.js', '.jsx', '.scss'],
modules: ['node_modules', path.resolve(__dirname, 'src')],
},
externals: {
react: 'react',
},
};
This is generating a dist/ folder with this content:
Seems everything is fine. The problem is when using this library in a React project, The components seems ok but fonts are not loaded correctly. The console throughs this message:
Failed to decode downloaded font: http://localhost:3000/static/js/GilroySemiBold-webfont.woff2
Fonts are being downloaded but not sure that files are not corrupt.
So, any clue about how can I use the fonts from the library??? Thanks in advance

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 5: Is it possible to output a javascript file non-bundled for configuration

I have a React TypeScript project that uses webpack 5.
I am trying to get a runtime-config.js file that I can change out in production by importing it as decribed in a similar Vuejs Docker issue.
I wanted to use File Loader but found that it's been deprecated in webpack 5
Here's what I want to achieve:
have ./runtime-config.js non bundled so that I can refer to it on the window object
easily reference that file in React (TypeScript) so that this dynamic configuration can be read.
Any help is appreciated.
Below is my webpack configuration:
// webpack.config.js
import path from 'path'
import { Configuration as WebpackConfiguration, DefinePlugin, NormalModuleReplacementPlugin } from 'webpack'
import { Configuration as WebpackDevServerConfiguration } from 'webpack-dev-server';
import HtmlWebpackPlugin from 'html-webpack-plugin'
import ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin'
import ESLintPlugin from 'eslint-webpack-plugin'
import tailwindcss from 'tailwindcss'
import autoprefixer from 'autoprefixer'
const CopyPlugin = require('copy-webpack-plugin');
interface Configuration extends WebpackConfiguration {
devServer?: WebpackDevServerConfiguration;
}
const config: Configuration = {
mode: 'development',
target: 'web',
devServer: {
static: path.join(__dirname, 'build'),
historyApiFallback: true,
port: 4000,
open: true,
liveReload: true,
},
output: {
publicPath: '/',
path: path.join(__dirname, 'dist'),
filename: '[name].bundle.js',
},
entry: {
main: './src/index.tsx',
'pdf.worker': path.join(__dirname, '../node_modules/pdfjs-dist/build/pdf.worker.js'),
},
module: {
rules: [
{
test: /\.(ts|js)x?$/i,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: [
'#babel/preset-env',
'#babel/preset-react',
'#babel/preset-typescript',
],
},
},
},
{
test: /\.(sa|sc|c)ss$/i,
use: [
'style-loader',
'css-loader',
'sass-loader',
{
loader: 'postcss-loader', // postcss loader needed for tailwindcss
options: {
postcssOptions: {
ident: 'postcss',
plugins: [tailwindcss, autoprefixer],
},
},
},
],
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
loader: 'file-loader',
options: {
outputPath: '../fonts',
},
},
{
test: /runtime-config.js$/,
use: [
{
loader: 'file-loader',
options: {
name: 'runtime-config.js',
},
},
],
},
],
},
resolve: {
extensions: ['.tsx', '.ts', '.js'],
},
plugins: [
new HtmlWebpackPlugin({
template: 'public/index.html',
}),
new NormalModuleReplacementPlugin(
/^pdfjs-dist$/,
(resource) => {
// eslint-disable-next-line no-param-reassign
resource.request = path.join(__dirname, '../node_modules/pdfjs-dist/webpack.js')
},
),
new CopyPlugin({
patterns: [
// relative path is from src
{ from: 'public/images', to: 'images' },
],
}),
// Add type checking on dev run
new ForkTsCheckerWebpackPlugin({
async: false,
}),
// Environment Variable for Build Number - Done in NPM scripts
new DefinePlugin({
VERSION_NUMBER: JSON.stringify(process.env.VERSION_NUMBER || 'development'),
}),
// Add lint checking on dev run
new ESLintPlugin({
extensions: ['js', 'jsx', 'ts', 'tsx'],
}),
],
devtool: 'inline-source-map',
};
export default config

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

Resolve Relative Path from node_modules to Dist folder with Webpack

I'm using React component as an NPM Package. in the component, I have SCSS file
with url(../iamges/img..) path, but actually, the images folder located in the Dist folder, how can I point Webpack to take the relative path from node_modules and serve it from images folder located in the Dist?
located in node_modules =>
background: url('../images/some-icon.svg') no-repeat center center;
Webpack config:
const webpack = require('webpack');
const path = require('path');
module.exports = {
entry: './src/index.js',
devtool: 'inline-module-source-map',
output: {
path: path.resolve(__dirname, '/dist'),
filename: 'bundle.js',
publicPath: '/',
},
module: {
rules: [
{
test: /\.js$/,
use: {
loader: 'babel-loader',
},
},
{
test: /\.scss$/,
use: [
{ loader: 'style-loader' },
{ loader: 'css-loader' },
{
loader: 'resolve-url-loader',
// options: {
// debug: true,
// root: path.join(__dirname, './dist/images'),
// includeRoot: true,
// absolute: true,
// },
},
{
loader: 'sass-loader',
options: {
sourceMap: true,
sourceMapContents: false,
},
},
],
},
{
test: /\.css$/,
loaders: ['style-loader', 'css-loader'],
},
{
test: /\.(png|jpg|gif|svg|eot|ttf|woff|woff2)$/,
use: {
loader: 'url-loader?name=/images/[name].[ext]',
options: {
limit: 10000,
},
},
},
],
},
resolve: {
extensions: ['.js', '.jsx'],
// modules: [path.resolve(__dirname, '/images'), 'node_modules'],
alias: {
'react-redux': path.resolve('./node_modules/react-redux'),
},
},
plugins: [new webpack.HotModuleReplacementPlugin()],
devServer: {
hot: true,
publicPath: '/dist/',
},
};
babel.config.js
module.exports = {
// presets: ['#babel/preset-env', '#babel/preset-react'],
plugins: [
'#babel/plugin-proposal-class-properties',
'#babel/plugin-proposal-export-default-from',
'#babel/transform-runtime',
],
sourceType: 'unambiguous',
presets: [
[
'#babel/preset-env',
{
targets: {
node: 'current',
},
},
],
'#babel/preset-react',
],
};
dist
-- images
-- index.html
ERROR:
ERROR in ./node_modules/comp/src/styles/details.scss (./node_modules/css-loader!./node_modules/resolve-url-loader!./node_modules/sass-loader/lib/loader.js??ref--5-3!./node_modules/compdetails/src/styles/details.scss)
Module not found: Error: Can't resolve '../images/icon.svg'
Anything referred through url('...') in css will be computed with reference to the path of deployed application (scss will not compute the path unless variable or function is not being used):
For example:
If your referred component SCSS module is having background: url('../images/some-icon.svg') no-repeat center center;
The final CSS compilation will be same (it is also because the component is not using any SCSS variables or functions to compute the final path).
So your application will always try to find that image as:
Example: http://localhost:3000/../images/some-icon.svg which is a problem.
(.. is referred as parent directory)
If you try to run your app with some sub-url (also known as sub context) as http://localhost:3000/sub-url/ and you keep your images parallel to sub-url folder it will automatically work.
-- /
|
|-- sub-url
|
|-- index.html
|-- images
|
|-- some-icon.svg
Another option can be override the component SCSS with yours.
You already found the solution to use resolve-url-loader, but in this case you need to import the component's scss file into you scss.
so your webpack config should look like:
const webpack = require('webpack');
const path = require('path');
module.exports = {
entry: './src/index.js',
devtool: 'inline-module-source-map',
output: {
path: path.resolve(__dirname, '/dist'),
filename: 'bundle.js',
publicPath: '/',
},
module: {
rules: [
{
test: /\.js$/,
use: {
loader: 'babel-loader',
},
},
{
test: /\.scss$/,
use: [
{ loader: 'style-loader' },
{ loader: 'css-loader' },
// CHANGE HERE
{
loader: 'resolve-url-loader',
options: {
root: '/images', // considering all your images are placed in specified folder. Note: this is just a string that will get as prefix to image path
includeRoot: true,
absolute: true,
},
},
{
loader: 'sass-loader',
options: {
sourceMap: true,
sourceMapContents: false,
},
},
],
},
{
test: /\.css$/,
loaders: ['style-loader', 'css-loader'],
},
{
test: /\.(png|jpg|gif|svg|eot|ttf|woff|woff2)$/,
use: {
loader: 'url-loader?name=/images/[name].[ext]',
options: {
limit: 10000,
},
},
},
],
},
resolve: {
extensions: ['.js', '.jsx'],
// modules: [path.resolve(__dirname, '/images'), 'node_modules'],
alias: {
'react-redux': path.resolve('./node_modules/react-redux'),
},
},
plugins: [new webpack.HotModuleReplacementPlugin()],
devServer: {
hot: true,
publicPath: '/dist/',
},
};
I hope it helps.

React, WebPack and Babel for Internet Explorer 10 and below produces SCRIPT1002: Syntax error

I've read multiple threads regarding similar issues and tried some propositions, but had no results.
I've followed few tutorials related to React.js and WebPack 3. As the result the application is working well on all browsers (at this moment) except IE 10 and below. The error points to bundle.js (once I'm using the configuration Nr.1):
SCRIPT1002: Syntax error and the line - const url = __webpack_require__(83);
With configuration Nr2., on local server - : SCRIPT1002: Syntax error - line with eval()
And the same configuration, but running on remote server produces a bit different error:
SCRIPT5009: 'Set' is undefine
WebPack configuration Nr1.:
const HtmlWebpackPlugin = require('html-webpack-plugin');
const HtmlWebpackPluginConfig = new HtmlWebpackPlugin({
template: './index.html',
filename: 'index.html',
inject: 'body'
})
module.exports = {
entry: './index.js',
output: {
filename: 'bundle.js'
},
module: {
loaders: [
{
test: /\.json$/,
exclude: /node_modules/,
loader: 'json-loader'
},
{
test: /\.css$/,
loader: "style-loader!css-loader"
}
],
rules: [
{
test: /\.js$/,
exclude: /(node_modules)/,
use: {
loader: 'babel-loader',
options: {
presets: ['env', 'react']
}
}
}
]
},
devServer: {
historyApiFallback: true,
contentBase: './'
},
plugins: [HtmlWebpackPluginConfig]
}
WebPack configuration Nr2.:
const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const PreloadWebpackPlugin = require('preload-webpack-plugin');
const ScriptExtHtmlWebpackPlugin = require('script-ext-html-webpack-plugin');
const StyleExtHtmlWebpackPlugin = require('style-ext-html-webpack-plugin');
const CompressionPlugin = require('compression-webpack-plugin');
const autoprefixer = require('autoprefixer');
const staticSourcePath = path.join(__dirname, 'static');
const sourcePath = path.join(__dirname);
const buildPath = path.join(__dirname, 'dist');
module.exports = {
stats: {
warnings: false
},
devtool: 'cheap-eval-source-map',
devServer: {
historyApiFallback: true,
contentBase: './'
},
entry: {
app: path.resolve(sourcePath, 'index.js')
},
output: {
path: path.join(__dirname, 'dist'),
filename: '[name].[chunkhash].js',
publicPath: '/'
},
resolve: {
extensions: ['.webpack-loader.js', '.web-loader.js', '.loader.js', '.js', '.jsx'],
modules: [
sourcePath,
path.resolve(__dirname, 'node_modules')
]
},
plugins: [
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('production')
}),
new webpack.optimize.ModuleConcatenationPlugin(),
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
filename: 'vendor.[chunkhash].js',
minChunks: Infinity
}),
new webpack.LoaderOptionsPlugin({
options: {
postcss: [
autoprefixer({
browsers: [
'last 3 version',
'ie >= 10'
]
})
],
context: staticSourcePath
}
}),
new webpack.HashedModuleIdsPlugin(),
new HtmlWebpackPlugin({
template: path.join(__dirname, 'index.html'),
path: buildPath,
excludeChunks: ['base'],
filename: 'index.html',
minify: {
collapseWhitespace: true,
collapseInlineTagWhitespace: true,
removeComments: true,
removeRedundantAttributes: true
}
}),
new PreloadWebpackPlugin({
rel: 'preload',
as: 'script',
include: 'all',
fileBlacklist: [/\.(css|map)$/, /base?.+/]
}),
new webpack.NoEmitOnErrorsPlugin(),
new CompressionPlugin({
asset: '[path].gz[query]',
algorithm: 'gzip',
test: /\.js$|\.css$|\.html$|\.eot?.+$|\.ttf?.+$|\.woff?.+$|\.svg?.+$/,
threshold: 10240,
minRatio: 0.8
})
],
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['env', 'react', 'es2015'],
plugins: ["transform-es2015-arrow-functions"]
}
},
include: sourcePath
},
{
test: /\.css$/,
exclude: /node_modules/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: [
{ loader: 'css-loader', options: { minimize: true } },
'postcss-loader',
'sass-loader'
]
})
},
{
test: /\.(eot?.+|svg?.+|ttf?.+|otf?.+|woff?.+|woff2?.+)$/,
use: 'file-loader?name=assets/[name]-[hash].[ext]'
},
{
test: /\.(png|gif|jpg|svg)$/,
use: [
'url-loader?limit=20480&name=assets/[name]-[hash].[ext]'
],
include: staticSourcePath
}
]
}
};
Here additionally I've added the es2015 to presets: ['env', 'react', 'es2015'] and plugins: ["transform-es2015-arrow-functions"] but it made no sense.
Well in case when the babel loader won't work at all of misconfiguration or something else, I think that the whole application won't start. I believe that something should be done with presets or their order... Need advice from experienced developer
UPDATE
I've changed devtool to inline-cheap-module-source-map and got error point to overlay.js -> const ansiHTML = require('ansi-html');
In your package.json file
change the version of webpack-dev-server to version "2.7.1" (or earlier).
"webpack-dev-server": "2.7.1"
Then do a npm install et voilĂ .
That solved the problem for me.
All versions after 2.7.1 gives me an error similar to yours.
Simply add devtools : "source-map" to your Webpack config like this:
const path = require('path');
module.exports = {
devtool: "source-map",
entry: ['babel-polyfill', path.resolve(__dirname, './js/main.js')],
mode: 'production',
output: {
path: __dirname+'/js/',
filename: 'main-webpack.js'
}
};
This will remove eval and change your source map to be supported by IE.
UPDATE I've changed devtool to inline-cheap-module-source-map and got error point to overlay.js -> const ansiHTML = require('ansi-html');
And to support ES6 syntax you have to compile your JavaScript code with Babel.

Resources