React with webpack cannot find tsx component dependency - reactjs

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
}),
],
};

Related

How to properly configure .png images in webpack?

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

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

Webpack Dev Server cannot find modules with Typescript if I use custom paths in tsconfig

I'm building a project from scratch on React + TypeScript and using the Webpack Dev server.
I want to use relative paths to components, which will be not strict for a more flexible development.
In my App.tsx, I'm trying to import component:
import EntityTypes from "components/EntityTypes/EntityTypes";
and getting an error
Module not found: Error: Can't resolve 'components/EntityTypes/EntityTypes' in '/home/eugene/prj/work/crud-react/src'
File by this path exists (/src/components/EntityTypes/EntityTypes.js) and exports the class like
export default EntityTypes;
My tsconfig.json:
{
"compilerOptions": {
"sourceMap": true,
"noImplicitAny": false,
"module": "commonjs",
"target": "es5",
"lib": [
"es2015",
"es2017",
"dom"
],
"removeComments": true,
"allowSyntheticDefaultImports": false,
"jsx": "react",
"allowJs": true,
"baseUrl": ".",
"paths": {
"components/*": [
"src/components/*"
]
}
}
}
webpack.config.js:
const HtmlWebPackPlugin = require( 'html-webpack-plugin' );
const path = require( 'path' );
module.exports = {
context: __dirname,
entry: './src/index.js',
resolve: {
extensions: ['.ts', '.tsx', '.js', '.jsx']
},
output: {
path: path.resolve( __dirname, 'dist' ),
filename: 'main.js',
publicPath: '/',
},
devServer: {
historyApiFallback: true
},
module: {
rules: [
{
test: /\.(tsx|ts)?$/,
loader: 'awesome-typescript-loader'
},
{
test: /\.js$/,
use: 'babel-loader',
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader'],
},
{
test: /\.(png|j?g|svg|gif)?$/,
use: 'file-loader'
}
]
},
plugins: [
new HtmlWebPackPlugin({
template: path.resolve( __dirname, 'public/index.html' ),
filename: 'index.html'
})
]
};
I've checked the documentation of typescript about "paths", the file is exists, I don't understand what the problem.
I have sorted out how to use paths for my files and make them flexible, that I can reorganize the project and manage paths easy without a lot of changes of strict relative paths.
The problem was related to configuration of the webpack.
Final configuration is next:
tsconfig.json
{
"compilerOptions": {
// ...
"paths": {
"~/components/*": [
"./src/components/*"
],
"~/services/*": [
"./src/services/*"
],
"~/interfaces/*": [
"./src/interfaces/*"
]
},
}
}
webpack.config.js
const path = require('path');
module.exports = {
// ...
resolve: {
// ...
alias: {
'~/components': path.resolve(process.cwd(), './src/components'),
'~/interfaces': path.resolve(process.cwd(), './src/interfaces'),
'~/services': path.resolve(process.cwd(), './src/services'),
}
},
}
Examples of usage
import {IEntities} from "~/interfaces/entities.interface";
// ...
import EntityForm from "~/components/EntityForm/EntityForm";
Just add tsconfig-paths-webpack-plugin into your webpack configuration:
const { cwd } = require('node:process');
const { resolve } = require('node:path');
const TsconfigPathsWebpackPlugin = require('tsconfig-paths-webpack-plugin');
module.exports = {
resolve: {
plugins: [
new TsconfigPathsWebpackPlugin({
configFile: resolve(cwd(), './tsconfig.json'),
})
]
}
};
And you don't need to duplicate paths configuration as webpack aliases.
You're using absolute imports, not relative ones. Try import EntityTypes from "./components/EntityTypes/EntityTypes";, assuming the file you're importing it into is on the same level as the components directory.

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