How to properly configure .png images in webpack? - reactjs

Iv'e created a storybook (build without create-react-app) which deployed to npm.
When trying to use its components in a different react application the .png images that suppose to be rendered together with the component are not loading at all (for .svg images I have set configuration which works fine).
In the storybook I'm trying to import the png as the following:
import borderPurpleDashed from '../../assets/borders/border-purple-dashed.png';
border-image: url(${borderPurpleDashed}) 30 / 1.5rem round;
Then in the react-app when importing the component it tries to load the image from its own localhost
“http://localhost:3000/a87d8c2e5e8293b0372b.png”
webpack.config.js
const path = require('path');
const webpack = require('webpack');
const svgrLoader = require.resolve('#svgr/webpack');
module.exports = {
mode: "production",
entry: './src/index.ts',
output: {
filename: 'index.js',
path: path.resolve(__dirname, 'dist'),
libraryTarget: 'umd',
clean: true
},
devtool: 'source-map',
resolve: {
extensions: [".tsx", ".ts", ".jsx", ".js", ".json"],
modules: ['node_modules']
},
externals: {
react: "react"
},
module: {
rules: [
{
test: /\.(ts|tsx)?$/,
use:['ts-loader'],
exclude: /node_modules/
},
{
test: /\.(css|s[ac]ss)$/i,
use: ['style-loader', 'css-loader', 'postcss-loader'],
},
{
test: /\.svg$/i,
type: 'asset',
resourceQuery: /url/, // *.svg?url
},
{
test: /\.svg$/i,
issuer: /\.[jt]sx?$/,
resourceQuery: {not: [/url/]}, // exclude react component if *.svg?url
use: [
{
loader: svgrLoader, options: {
svgoConfig: {
plugins: [
{
name: 'removeViewBox',
active: false
}
]
}
}
},
]
},
{
test: /\.(woff(2)?|eot|ttf|otf|)$/,
type: 'asset/inline',
},
{
test: /\.(?:ico|gif|png|jpg|jpeg|)$/i,
type: 'asset/resource',
},
],
},
plugins: [
new webpack.ProvidePlugin({
FroalaEditor: 'file_name'
})
]
};
tsconfig.json
{
"compilerOptions": {
"allowSyntheticDefaultImports": true,
"target": "es5",
"module": "es2015",
"jsx": "react",
"strict": true,
"esModuleInterop": true,
"moduleResolution": "node",
"noUnusedLocals": true,
"types": ["node", "mocha", "jest","cypress", "cypress-file-upload","./cypress/support"],
"lib": ["es5","es2015","es2016", "dom","esnext"],
"outDir": "./dist/",
"sourceMap": true,
"declarationMap": true,
"declaration": true,
"resolveJsonModule": true,
},
"include": [
"src",
"node_modules/cypress/types/cypress-global-vars.d.ts"
],
"exclude": ["node_modules", "dist", "**/*.stories.tsx", "**/*.test.tsx"]
}

Did you try file-loader?
In webpack.config.js, add this in the rule array:
{
test: /\.(png|jpe?g|gif)$/i,
use: [
{
loader: 'file-loader',
},
]
}
OR
You could refer to the storybook documentation for assets

Related

Trying to render Froala Editor in React App, but the app crashes

I'm using React 17 with TypeScript and Webpack 5
and I'm trying to render Froala Editor from 'wysiwyg' package but I get this Error:
'FroalaEditorView' cannot be used as a JSX component. Its instance type 'FroalaEditor' is not a valid JSX element.The types returned by 'render()' are incompatible between these types. Type 'React.ReactNode' is not assignable to type 'import("/Users/Al/Desktop/projects/privateLib/node_modules/#types/react-transition-group/node_modules/#types/react/index").ReactNode. Type '{}' is not assignable to type 'ReactNode'.
Note: When I'm trying to render the Froala Editor in the app that I generate with CRA, I don't have any issue.
Any idea how to solve this problem?
Webpack Config:
const path = require('path');
const webpack = require('webpack');
const svgrLoader = require.resolve('#svgr/webpack');
module.exports = {
mode: "production",
entry: './src/index.ts',
output: {
filename: 'index.js',
path: path.resolve(__dirname, 'dist'),
libraryTarget: 'umd',
clean: true
},
devtool: 'source-map',
resolve: {
extensions: [".tsx", ".ts", ".jsx", ".js", ".json"],
modules: ['node_modules']
},
externals: {
react: "react"
},
module: {
rules: [
{
test: /\.(ts|tsx)?$/,
use:['ts-loader'],
exclude: /node_modules/
},
{
test: /\.(css|s[ac]ss)$/i,
use: ['style-loader', 'css-loader', 'postcss-loader'],
},
{
test: /\.svg$/i,
type: 'asset',
resourceQuery: /url/, // *.svg?url
},
{
test: /\.svg$/i,
issuer: /\.[jt]sx?$/,
resourceQuery: {not: [/url/]}, // exclude react component if *.svg?url
use: [
{
loader: svgrLoader, options: {
svgoConfig: {
plugins: [
{
name: 'removeViewBox',
active: false
}
]
}
}
},
]
},
{
test: /\.(woff(2)?|eot|ttf|otf|)$/,
type: 'asset/inline',
},
{
test: /\.(?:ico|gif|png|jpg|jpeg|)$/i,
type: 'asset/resource',
},
],
},
plugins: [
new webpack.ProvidePlugin({
FroalaEditor: 'file_name'
})
]
};
TS Config:
{
"compilerOptions": {
"allowSyntheticDefaultImports": true,
"target": "es5",
"module": "es2015",
"jsx": "react",
"strict": true,
"esModuleInterop": true,
"moduleResolution": "node",
"noUnusedLocals": true,
"types": ["node", "mocha", "jest","cypress", "cypress-file-upload","./cypress/support"],
"lib": ["es5","es2015","es2016", "dom","esnext"],
"outDir": "./dist/",
"sourceMap": true,
"declarationMap": true,
"declaration": true,
"resolveJsonModule": true,
},
"include": [
"src",
"node_modules/cypress/types/cypress-global-vars.d.ts"
],
"exclude": ["node_modules", "dist", "**/*.stories.tsx", "**/*.test.tsx"]
}
Render Code:
<FroalaEditorView
tag="textarea"
onModelChange={(newContent: ChangeEvent<HTMLTextAreaElement>) => props.onChange(newContent)}
config={textEditorConfig}
model={props.value}
/>
I’ve had the same issue with the FroalaEditor component in one of my projects (React 17 and Webpack 5). Although Typescript would complain about the component not being JSX, I could still build and run my application just fine. I managed to please Typescript (get rid of the error) by updating #types/react:
yarn add #types/react#latest
For npm it should be (not 100% sure):
npm install –save #types/react

React with webpack cannot find tsx component dependency

I am adding Typescript support to an older React application. It was not created with create-react-app. I've installed typescript and ts-loader. I added a tsconfig file which allows js files. And I updated the webpack.config.json file to use ts-loader to handle ts and tsx files. But when I tried to convert a very simple component from .js to .tsx, it does not compile. I get the error:
"This dependency was not found:
* Components/Molecules/SectionA/ButtonBarFooter in ./src/components/Organisms/SectionA/Form.js
To install it, you can run: npm install --save Components/Molecules/SectionA/ButtonBarFooter
I thought that maybe it had something to due with configuring aliases in our webpack config because Components is an alias. So I duplicated it into the tsConfig. But that has not fixed this error. Why can't ButtonBarFooter.tsx be found by the parent component on compile?
tsconfig.json:
{
"compilerOptions": {
"sourceMap": true,
"target": "es5",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noFallthroughCasesInSwitch": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"declaration": true,
"emitDeclarationOnly": true,
"noEmit": true,
"jsx": "react",
"baseUrl": "./src",
"paths": {
"Actions/*": ["actions/*"],
"Components/*": ["components/*"],
"Assets/*": ["assets/*"],
"Util/*": ["util/*"],
"Routes/*": ["routes/*"],
"Constants/*": ["constants/*"],
"Helpers/*": ["helpers/*"],
"Api/*": ["api/*"]
}
},
"include": ["src"]
}
webpack.config.json (resolve is commented out because when it was active, it couldn't find 35 modules, which were JS components!):
'use strict';
/**
* Webpack Config
*/
const path = require('path');
const fs = require('fs');
const webpack = require('webpack');
const FriendlyErrorsWebpackPlugin = require('friendly-errors-webpack-plugin');
// Webpack uses `publicPath` to determine where the app is being served from.
// In development, we always serve from the root. This makes config easier.
const publicPath = '/';
// Make sure any symlinks in the project folder are resolved:
const appDirectory = fs.realpathSync(process.cwd());
const resolveApp = (relativePath) => path.resolve(appDirectory, relativePath);
// plugins
const HtmlWebPackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
// the path(s) that should be cleaned
let pathsToClean = ['dist', 'build'];
// the clean options to use
let cleanOptions = {
root: __dirname,
verbose: false, // Write logs to console.
dry: false,
};
module.exports = {
entry: ['babel-polyfill', 'react-hot-loader/patch', './src/index.js'],
output: {
// The build folder.
path: resolveApp('dist'),
filename: 'static/js/[name].[hash:8].js',
publicPath: publicPath,
hotUpdateChunkFilename: 'hot/hot-update.js',
hotUpdateMainFilename: 'hot/hot-update.json',
},
devServer: {
contentBase: './src/index.js',
host: '0.0.0.0',
compress: true,
port: 9000, // port number
historyApiFallback: true,
quiet: true,
disableHostCheck: true,
},
devtool: 'inline-source-map',
// resolve alias (Absolute paths)
resolve: {
alias: {
Actions: path.resolve(__dirname, 'src/actions/'),
Components: path.resolve(__dirname, 'src/components/'),
Assets: path.resolve(__dirname, 'src/assets/'),
Util: path.resolve(__dirname, 'src/util/'),
Routes: path.resolve(__dirname, 'src/routes/'),
Constants: path.resolve(__dirname, 'src/constants/'),
Helpers: path.resolve(__dirname, 'src/helpers/'),
Api: path.resolve(__dirname, 'src/api/'),
},
},
module: {
rules: [
{
test: /\.(ts|tsx)$/,
exclude: /node_modules/,
resolve: {
extensions: ['.ts', '.tsx'],
},
use: 'ts-loader',
},
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
//loader: "source-map-loader",
},
},
{
test: /\.html$/,
use: [
{
loader: 'html-loader',
options: { minimize: true },
},
],
},
{
test: /\.css$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
// you can specify a publicPath here
// by default it uses publicPath in webpackOptions.output
publicPath: '/',
hmr: process.env.NODE_ENV === 'production',
},
},
'css-loader',
],
},
{
test: /\.(png|jpg|gif)$/,
use: [
{
loader: 'url-loader',
options: {
limit: 10000,
name: 'static/media/[name].[hash:8].[ext]',
},
},
],
},
{
test: /\.(woff|woff2|eot|ttf|svg)$/,
loader: 'url-loader?limit=100000',
},
// Scss compiler
{
test: /\.scss$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
hmr: process.env.NODE_ENV === 'production',
},
},
// Translates CSS into CommonJS
'css-loader',
// Compiles Sass to CSS
'sass-loader',
],
},
],
},
// resolve: {
// // Add '.ts' and '.tsx' as resolvable extensions.
// extensions: ["", ".webpack.js", ".web.js", ".ts", ".tsx", ".js"],
// },
performance: {
hints: process.env.NODE_ENV === 'production' ? 'warning' : false,
},
plugins: [
new FriendlyErrorsWebpackPlugin(),
new CleanWebpackPlugin({
pathsToClean,
cleanOptions,
}),
new HtmlWebPackPlugin({
template: './public/index.html',
filename: './index.html',
}),
new MiniCssExtractPlugin({
// Options similar to the same options in webpackOptions.output
// all options are optional
filename: '[name].css',
chunkFilename: '[id].css',
ignoreOrder: false, // Enable to remove warnings about conflicting order
}),
],
};

'SocketClient is not a constructor' in react-refresh-webpack-plugin

I have a typescript react project where I try to add the react-refresh-webpack-client and get this error:
my webpack config:
import HtmlWebpackPlugin from 'html-webpack-plugin';
import UglifyJsPlugin from 'uglifyjs-webpack-plugin';
import ReactRefreshWebpackPlugin from '#pmmmwh/react-refresh-webpack-plugin';
import ReactRefreshTypeScript from 'react-refresh-typescript';
import { HotModuleReplacementPlugin } from 'webpack';
const isDevelopment = process.env.NODE_ENV !== 'production';
module.exports = {
resolve: {
extensions: [".ts", ".tsx", ".js", ".jsx"]
},
optimization: {
minimizer: [new UglifyJsPlugin()],
splitChunks: {
chunks: 'all'
}
},
mode: isDevelopment ? 'development' : 'production',
devServer: {
port: process.env.WEBPACK_PORT,
historyApiFallback: true,
hot: true,
},
module: {
rules: [
{
test: /\.[jt]sx?$/,
exclude: /node_modules/,
use: [
{
loader: require.resolve('ts-loader'),
options: {
getCustomTransformers: () => ({
before: isDevelopment ? [ReactRefreshTypeScript()] : [],
}),
// `ts-loader` does not work with HMR unless `transpileOnly` is used.
transpileOnly: isDevelopment,
},
},
],
},
{ enforce: "pre",
test: /\.js$/,
exclude: /node_modules/,
loader: 'source-map-loader'
},
{
test: /\.(png|jpe?g|gif)$/i,
type: 'asset/resource'
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader'],
},
],
},
plugins: [
new HtmlWebpackPlugin({
template: './client/index.html',
filename: './index.html',
}),
isDevelopment && new HotModuleReplacementPlugin(),
isDevelopment && new ReactRefreshWebpackPlugin(),
],
entry: {
main: ['./client/index.tsx'],
vendor: ['lodash', 'react', '#material-ui/core'],
},
devtool: 'source-map'
};
here is my tsconfig file:
{
"compilerOptions": {
"target": "es5",
"module": "es2015",
"jsx": "react",
"strict": true,
"alwaysStrict": true,
"noImplicitReturns": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
},
"exclude": [
"node_modules"
]
}
I already removed react-hot-loader from my code.
can't find any example of react-refresh with typescript, what am I missing?
what could be my problem? thank you!
I would use export default { instead of module.exports = {
You need to use the latest refresh plugin (0.5.0), explanation is in this issue.

Visual Studio Code Intellisense doesn't work with Opencv.JS?

I have reactjs + typescript web application which suppose to use opencv.js library for doing some vision tasks. However I can't make intellisense to work in my Visual Studio Code IDE for that library. I load library as following
var CV = require('../opencvLibs/build_js/bin/opencv_js.js');
class InnerApp extends React.Component{
componentDidMount(){
CV["onRuntimeInitialized"]= () => {
let mat = new CV.Mat();
console.log(mat.size());
mat.delete();
}
}
render(){
return(
<Provider rootStore = {new RootStore()}>
<App/>
</Provider>
)
}
}
ReactDOM.render(
<Provider>
<InnerApp />
</Provider>,
document.getElementById('root'));
As you can see I am logging into console empty mat size just to check if library is working fine and I am getting width and height logged properly which indicates that library is loaded successfully.
I tried to add jsconfig.json file as I saw that as potential solution in official Visual Studio Code docs, however that didn't work.
tsconfig.json
{
"compilerOptions": {
"allowJs": true,
"module": "commonjs",
"target": "es6",
"noImplicitAny": false,
"esModuleInterop": true,
"removeComments": true,
"preserveConstEnums": true,
"jsx": "react",
"sourceMap": true,
"experimentalDecorators": true,
"lib": ["es6","dom"],
"typeRoots": [
"typings",
"node_modules/#types"
]
},
"files":[
"opencvLibs/build_js_wasm/bin/opencv.js"
]
}
jsconfig.json
{
"compilerOptions": {
"target": "ES6",
"module": "commonjs"
},
"exclude": [
"node_modules",
"**/node_modules/*"
],
"include": [
"opencvLibs/build_js/bin/opencv.js"
],
"typeAcquisition": {
"include": [
"opencvLibs/build_js/bin/opencv.js"
]
}
}
webpack.dev.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpack = require('webpack');
const HOST = process.env.HOST || '127.0.0.1';
const PORT = process.env.PORT || '9000';
const config = {
mode: 'development',
entry: {
app: './src/index.tsx',
},
output: {
path: path.resolve(__dirname, '../dist'),
filename: '[name].bundle.js'
},
resolve: {
extensions: ['.ts', '.tsx', '.js']
},
devtool: 'eval-cheap-module-source-map',
module: {
rules: [{
test: /\.tsx?$/,
use: [{
loader: 'ts-loader',
options: {
onlyCompileBundledFiles: true,
}
}]
},
{
test: /\.(s?)css$/,
use: ['style-loader','css-loader','sass-loader']
},
{
test: /\.otf$/,
use: {
loader: 'file-loader',
options: {
name: 'dist/fonts/[name].[ext]'
}
}
},
{
//test: /\.(png|jpe?g|gif|svg)$/
test: /\.(eot|woff|woff2|ttf|svg|png|jpe?g|gif)(\?\S*)?$/,
use: [{
loader: 'url-loader',
//loader: 'url?limit=100000&name=[name].[ext]',
options: {
limit: 8192
}
}]
},
],
},
devServer: {
host: HOST,
port: PORT,
compress: true,
inline: true,
historyApiFallback: true,
hot: true,
overlay: true,
open: true,
},
plugins: [
new webpack.LoaderOptionsPlugin({
options:{
scripts: [
"../opencvLibs/build_js_wasm/bin/opencv.js"
]}
}),
new webpack.HotModuleReplacementPlugin({
}),
new HtmlWebpackPlugin({
template: 'src/index.html',
title: 'React Mobx Starter',
inject: 'body'
}),
],
node: {
fs: 'empty'
},
};
module.exports = config;
Expected result would be that intellisense works when I type "CV."
Thanks for your help!

Webpack+ tsconfig + dynamic import throwing NoEmit error for .d.ts files

I'm having a strange issue understanding how webpack, tsconfig and .d.ts files are working together.
I've the following project structure:
The ScriptsApp contains an #types folder as follows:
My tsconfig.json is as follows:
{
"compilerOptions": {
"target": "ES2018",
"module": "esnext",
"lib": [
"es6",
"dom",
"scripthost",
"es2018",
"es2018.promise"
],
"jsx": "react",
"sourceMap": true,
"outDir": "./.out/",
"noImplicitAny": true,
"strictFunctionTypes": true,
"alwaysStrict": true,
"moduleResolution": "node",
"typeRoots": ["node_modules/#types", "ScriptsApp/#types"]
},
"include": ["./ScriptsApp/**/*.tsx", "./ScriptsApp/**/*.ts", "ScriptsApp/#types"],
"exclude": ["node_modules"],
"files": ["ScriptsApp/indexApp.tsx"]
}
And this is my webpack config:
const path = require("path");
const webpack = require("webpack");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const ForkTsCheckerWebpackPlugin = require("fork-ts-checker-webpack-plugin");
module.exports = {
mode: "development",
output: {
filename: "[name].bundle.[hash].js",
path: path.join(__dirname, ".out/"),
chunkFilename: "[name].chunk.js",
publicPath: "/",
hotUpdateChunkFilename: ".hot/hot-update.js",
hotUpdateMainFilename: ".hot/hot-update.json"
},
optimization: {
runtimeChunk: {
name: "manifest"
},
splitChunks: {
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: "vendors",
priority: -20,
chunks: "all"
}
}
}
},
target: "web",
devServer: {
contentBase: ".out/",
hot: true
},
plugins: [
new webpack.NamedModulesPlugin(),
new webpack.HotModuleReplacementPlugin(),
new HtmlWebpackPlugin({
inject: true,
template: path.join(__dirname, "./index.html")
}),
new ForkTsCheckerWebpackPlugin({
checkSyntacticErrors: true,
tslint: "./tslint.json",
tslintAutoFix: true,
tsconfig: "./tsconfig.json",
async: false,
reportFiles: ["ScriptsApp/**/*"]
})
],
module: {
rules: [
{
test: /\.(png|jpg|ico)$/,
loader: "file-loader",
options: {
name: ".img/[name].[ext]?[hash]",
publicPath: "/"
}
},
{
test: /\.(woff(2)?|ttf|eot|svg|otf)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
loader: "file-loader",
options: {
name: ".fonts/[name].[ext]?[hash]",
publicPath: "/"
}
},
{
test: /\.(ts|tsx)$/,
use:"ts-loader"
},
{
test: /\.js$/,
loader: "source-map-loader"
},
{
test: /\.scss$/,
use: [
{
loader: "style-loader" // creates style nodes from JS strings
},
{
loader: "css-loader",
options: {
sourceMap: true
}
},
{
loader: "resolve-url-loader"
},
{
loader: "sass-loader",
options: {
sourceMap: true
}
}
]
}
]
},
resolve: {
extensions: [".js", ".ts", ".tsx", ".scss", ".css", ".png", ".ico", ".json"]
},
devtool: "source-map"
};
Now my question:
I'm trying to use dynamic imports in one of my React components as follows:
private loadComponentFromPath(path: string) {
import(`../../ScriptsApp/${path}`).then(component =>
this.setState({
component: component.default
})
);
}
As soon as I added dynamic import, my build started showing this error for all the .d.ts files inside ScriptsApp/#types folder
WARNING in ./ScriptsApp/#types/react-adal.d.ts
Module build failed (from ./node_modules/ts-loader/index.js):
Error: TypeScript emitted no output for C:\code\AzureCXP-Eng\src\Applications\AzureCxpWebSite\WebSite\FeedbackSrc\App\ScriptsApp\#types\react-adal.d.ts.
at makeSourceMapAndFinish (C:\code\AzureCXP-Eng\src\Applications\AzureCxpWebSite\WebSite\FeedbackSrc\App\node_modules\ts-loader\dist\index.js:78:15)
at successLoader (C:\code\AzureCXP-Eng\src\Applications\AzureCxpWebSite\WebSite\FeedbackSrc\App\node_modules\ts-loader\dist\index.js:68:9)
at Object.loader (C:\code\AzureCXP-Eng\src\Applications\AzureCxpWebSite\WebSite\FeedbackSrc\App\node_modules\ts-loader\dist\index.js:22:12)
# ./ScriptsApp lazy ^\.\/.*$ namespace object ./#types/react-adal.d.ts
# ./ScriptsApp/Routes/AppRoutesList.tsx
# ./ScriptsApp/Routes/Routes.tsx
# ./ScriptsApp/Components/App.tsx
# ./ScriptsApp/indexApp.tsx
# ./ScriptsApp/index.tsx
# multi webpack-hot-middleware/client?reload=true ./ScriptsApp/index.tsx
How I can currently make the error go away?
Move #types folder outside the ScriptsApp, or
Not use dynamic imports
Rename all .d.ts files under ScriptsApp/#types to .interface.ts --> most baffling to me
I'm not able to understand why though. I'm also new to the entire technology stack so sorry if I'm missing something obvious. Please explain this behavior. Also, any suggestions on improving the configs are also much appreciated. Thanks.
From another GitHub issue you can do this in your tsconfig.json file.
{
"compilerOptions": {
"target": "ES6",
"jsx": "react",
"noEmit": true
},
"exclude": [
"node_modules",
"dev_server.js"
]
}
Could you try to add the line "noEmit": false.
The following code in tsconfig.json should ensure that the errors from within node_modules will not be reported.
{
compilerOptions: {
skipLibCheck: true
}
}

Resources