React Images Import in Typescript - reactjs

I've set my own react project with typescript and react and my own webpack config. Hence I did or did not something somewhere wrong and I can't figure out what.
My problem is that I can't import my images.
I've tried the solutions from those guides but to no avail: https://medium.com/better-programming/how-to-display-images-in-react-dfe22a66d5e7
My setup is as follows:
src > assets/components/theme index.tsx custom.d.ts
assets > img > Logo.png
components > different folders for components & App.tsx
Index.tsx and custom.d.ts are next to each other.
In my webpack config I have this:
{
test: /\.(png|svg|jpg|jpeg|gif)$/i,
type: 'asset/resource',
}
In my custom.d.ts file I have this:
declare module '*.jpg'
declare module '*.png'
declare module '*.jpeg'
declare module '*.gif'
I am trying to import the file like this: import Logo from '../../assets/img/Logo'
I am getting this error: Cannot find module '../../assets/img/Logo' or its corresponding type declarations.ts(2307)
Please let me know if you need additional information.
Thanks!

You have asset/resource in your config, but said your structure is assets/img, try changing asset to assetsin your config, or creating the path asset/resource.

Related

Cannot import local fonts with TypeScript

I am trying to import font files on React with TypeScript project, but it doesn't recognize it as a font file, but instead, it looks at it as a module
Folder structure:
In my index.tsx file, I imported the font I need, and exported Font constant:
import helveticaNeueLightWoff from './HelveticaNeueW02-45Ligh.woff';
import helveticaNeueLightWoff2 from './HelveticaNeueW02-45Ligh.woff2';
import helveticaNeueMediumWoff from './HelveticaNeueW02-67MdCn.woff';
import helveticaNeueMediumWoff2 from './HelveticaNeueW02-67MdCn.woff2';
import helveticaNeueBoldWoff from './HelveticaNeueW02-75Bold.woff';
import helveticaNeueBoldWoff2 from './HelveticaNeueW02-75Bold.woff2';
import helveticaNeueBoldCnWoff from './HelveticaNeueW02-77BdCn.woff';
import helveticaNeueBoldCnWoff2 from './HelveticaNeueW02-77BdCn.woff2';
const Fonts = {
helveticaNeueLightWoff,
helveticaNeueLightWoff2,
helveticaNeueMediumWoff,
helveticaNeueMediumWoff2,
helveticaNeueBoldWoff,
helveticaNeueBoldWoff2,
helveticaNeueBoldCnWoff,
helveticaNeueBoldCnWoff2,
};
export default Fonts;
I use url-loader(I also tried with file-loader). This is my webpack.config.ts
{
test: /\.(woff|woff2)(\?v=\d+\.\d+\.\d+)?$/,
use: {
loader: 'url-loader',
options: {
// Limit at 50k. Above that it emits separate files
limit: 50000,
// url-loader sets mimetype if it's passed.
// Without this it derives it from the file extension
mimetype: 'application/font-woff',
// Output below fonts directory
name: './fonts/[name].[ext]',
},
},
},
This is the error I get: Cannot find module './HelveticaNeueW02-45Ligh.woff'
What could be the cause of this problem?
You need to declare the font file formats as modules so that TypeScript can parse them correctly.
create a fonts.d.ts file and add the following to it
declare module '*.woff';
declare module '*.woff2';
It tells TypeScript that the font filetypes are valid import modules.
The "d.ts" file format is used to provide typescript type information about an API that's written in JavaScript, or the shape of the third party imports.
Make sure that the types file is considered in the include section in tsconfig.json. A nice approach is to have a root typings directory in your project, then append typings/**/*.d.ts on include.
Completion of the previous answer for expo user who would face a similar issue :
I faced the same issue, and declaring the module was enough to import fonts but not to actually load these.
I was using expo-font, and Typescript was complaining about the type of the result. To make it work, I created the same file with the following content :
declare module "*.ttf" {
const value: import("expo-font").FontSource;
export default value;
}
This tells that the module imported will have the type FontSource that comes from expo-font library. I was then able to load my font :)

Importing images in TypeScript React - "Cannot find module"

I am trying to import images to use inside a React component with TypeScript. The bundler I'm using is Parcel (not Webpack).
I have created a .d.ts file inside the project with the image file extension, and included it inside tsconfig.json. However, when I try to import an image, TS yells at me about Cannot find module.
My project structure:
+ src
+ assets
- image.jpg
+ components
- Box.tsx
- App.tsx
- index.d.ts
- index.html
- index.tsx
- tsconfig.json
- tslint.json
I tried to import the image in App.tsx like this. VS Code underlined '../assets/image.jpg' and said Cannot find module '../assets/image.jpg'.
import * as React from 'react';
import * as img from '../assets/image.jpg';
const Box = props => {
// do things...
}
export default Box;
The discussions I found online point to the need of defining a .d.ts file myself, so I created that index.d.ts file with this line.
declare module '*.jpg';
Then added "include": ["./src/index.d.ts"] inside tsconfig.json, after "compilerOptions" : {...}.
What did I miss? How can I fix the error TS is throwing?
create index.d.ts file in folder src,and add this line
declare module '*.jpg';
If you literally wrote "include": ["./src/index.d.ts"] in tsconfig.json and you don't have a "files" setting, that means the project defined by tsconfig.json includes only the single file ./src/index.d.ts. When you open any other file in VS Code, VS Code uses a separate language service instance that doesn't use your tsconfig.json. Adjust your "include" setting to match all the .ts and .tsx files in your project, or just delete it and rely on the default behavior of including all files under the directory containing tsconfig.json.
Round 2
TypeScript is ignoring index.d.ts because it assumes that index.d.ts is generated from index.tsx and index.tsx is more likely to be up to date. Name your index.d.ts file something else, e.g., declaration.d.ts.
Create module/type
# src/types/images.d.ts
declare module '*.jpg';
declare module '*.jpeg';
Change tsconfig.json
{
"compilerOptions": {
"typeRoots" : ["node_modules/#types", "src/types"]
}
}
there is a work around to it
for example,
import logo from "../../assets/logo.png"
change this to
const logo = require("../../assets/logo.png")
This took me about an hour so I'm going to leave the solution that worked for me.
Matt McCutchen's solution half-worked for me, but I was still facing a VSCode error. To combat this, I moved my tsconfig.json and index.d.ts to the root directory, NOT the src. Now you want your tsconfig.json to look like this:
"include": ["src", "index.d.ts"]
And for your index.d.ts, this:
declare module '*.png';
declare module '*.jpg';
(^ tweak to your typing needs)
There can be many solutions to this problem
Solution #1:
Use require to include image
<img src={require('../../assets/logo.png')} alt="" />
Solution #2:
Instead of importing images as
import logo from "../../assets/logo.png"
Import as
const logo = require("../../assets/logo.png");
then use it like
<img src={logo} alt="" />
Solution #3:
There is a react-app-env.d.ts file in your src folder.
If you don't see it, create a new file in the src folder named react-app-env.d.ts.
Now in your react-app-env.d.ts, add this code.
declare module "*.png";
declare module "*.svg";
declare module "*.jpeg";
declare module "*.jpg";
Solution #4:
Create declaration.d.ts in your src folder.
Then add following text in it.
declare module "*.png";
declare module "*.svg";
declare module "*.jpeg";
declare module "*.jpg";
Now you have to make your tsconfig.json look like this:
{
"compilerOptions": {},
"include": [
"src",
"src/declaration.d.ts",
]
}
Solution #5:
Create a types folder in your src folder and add images.d.ts in this folder.
Add below text in it.
declare module "*.png";
declare module "*.svg";
declare module "*.jpeg";
declare module "*.jpg";
Now configure tsconfig.json like this:
{
"compilerOptions": {
"typeRoots": [
"node_modules/#types",
"src/types"
],
}
There should be a file called "react-app-env.d.ts" that is created when you use create-react-app. This file classes all types of image files and many more as modules that can be imported. inside the file there should be the following:
/// <reference types="react-scripts" />
For "react": "^18.2.0" with Typescript do the following:
Create a file called: declaration.d.ts in your src/ dir.
Add this lines of code:
declare module "*.jpg"
declare module "*.png"
That's it the error should be turned off.
Good lock!
I declared multiple image types, and had to put them in separate .d.ts files to make VS Code happy:
src/types/image.jpg.d.ts:
declare module '*.jpg' {
import { ImageSourcePropType } from 'react-native'
const content: ImageSourcePropType
export default content
}
src/types/image.png.d.ts:
declare module '*.png' {
import { ImageSourcePropType } from 'react-native'
const content: ImageSourcePropType
export default content
}
src/types/image.svg.d.ts:
declare module '*.svg' {
import React from 'react'
import { SvgProps } from 'react-native-svg'
const content: React.FC<SvgProps>
export default content
}
No tweaks to tsconfig, etc required.
Create a global.d.ts file inside your src directory or any rootDir
declare module "*.png" {
export default "" as string
}
This will make use of an asset, in this case png image and also clear a vscode error
I've pasted:
/// <reference types="react-scripts" />
from an older project in my: react-app-env.d.ts and it worked.
In the latest versions of CRA (when TS is the chosen language), this file is automatically added to the src folder and contains the single line shown above. It is a directive to reference types from react-scripts.
This is worked for me
declare module "*.png" {
const src: string
export default src
}
I test all of the replies and found the answer.
First, create a file with the name .d.ts in your route folder.
Then copy these lines into that.
declare module "*.png" {
export default "" as string;
}
declare module "*.svg" {
export default "" as string;
}
declare module "*.jpeg" {
export default "" as string;
}
declare module "*.jpg" {
export default "" as string;
}
Finally, go to tsconfig.json file in your route folder. and define new child.
{
"include": ["src", ".d.ts"]
}
your're go to go.
This error happens when you not included react-app-env.d.ts file in your src folder
becoz you need two line of code for get rid of this error ==>
<reference types="react-scripts" />
I fixed adding file index.d.ts in root:
Paste the following code inside of it: <reference types="react-scripts"
-
inside tsconfig.json, add: "include": ["src", "index.d.ts"]

Create-react-app doesn't allow import component.js from node_modules?

I received error when try to import { PrimaryButton } from 'my-npm-modules/src/button' ( which is a flowtype src jsx file with extension .js)?
Is it because the create-react-app have config to NOT do flowtype processing for files in node_modules?
Module parse failed: /Users/me/live-demo/node_modules/my-npm-modules/src/button.js Unexpected token (2:35)
You may need an appropriate loader to handle this file type.
| //#flow
| import React from 'react';
| export function PrimaryButton(props: {
| text: string;
| onClick: ()=>void
When I put the button.js inside the live-demo project, it works fine.
It seems it did exclude the node_modules folder for performance reason.
So I endup compile the flow-typed jsx --> normal js files, and provided js.flow at the same output folder for sake of consumer flowtype support.

Importing self-created libraries in reactjs

I'm using React and ES6 using babel and webpack. I am very new to this ecosystem.
I am trying to import some common utility functions into my jsx file but react is unable to find the file
homepage.jsx
var pathToRoot = './../..';
import path from 'path';
import React from 'react';
import ReactDOM from 'react-dom';
var nextWrappedIndex = require(path.join(pathToRoot,'/lib/utils.js')).nextWrappedIndex;
//some react/JSX code
utils.js
var nextWrappedIndex = function(dataArray) {
//some plain js code
return newIndex;
}
exports.nextWrappedIndex = nextWrappedIndex;
Directory structure is as follows:
src
|--app.js
|--components
| |--homepage
| |--homepage.jsx
|
|--lib
| |--utils.js
I am on a windows 10 machine and was facing issues during compilation providing the path by any other means. Using path.join solved compilation issue but the browser while rendering throws this error
Uncaught Error: Cannot find module '../../lib/utils.js'.
How do I accomplish this?
Also, is this the best way to do it(if altogether it is way it is supposed to be done in such ecosystem)?
One of the best and easiest way I have found in such a setup is to use Webpack aliases.
Webpack aliases will simply associate an absolute path to a name that you can use to import the aliased module from anywhere. No need to count "../" anymore.
How to create an alias?
Let's imagine that your Webpack config is in the parent folder of your src folder.
You would add the following resolve section in your config.
const SRC_FOLDER = path.join(__dirname, 'src')
resolve: {
alias: {
'my-utils': path.join(SRC_FOLDER, 'lib', 'utils')
}
}
Now, anywhere in your app, in any of your modules or React component you can do the following:
import utils from 'my-utils'
class MyComponent extends React.component {
render () {
utils.doSomething()
}
}
Small note about this method. If you run unit tests with a tool like enzyme and you don't run the component tested through Webpack, you will need to use the babel-plugin-webpack-alias.
More info on Webpack website: Webpack aliases
I solved this by replacing
var nextWrappedIndex = require(path.join(pathToRoot,'/lib/utils.js')).nextWrappedIndex;
with
import nextWrappedIndex from './../../lib/utils.js';
I tried to reproduce your code and Webpack printed me the following error:
WARNING in ./app/components/homepage/homepage.jsx
Critical dependencies:
50:0-45 the request of a dependency is an expression
# ./app/components/homepage/homepage.jsx 50:0-45
It means that Webpack couldn't recognize your require() expression because it works only with static paths. So, it discourages the way you are doing.
If you would like to avoid long relative paths in your import, I'd recommend you to set up Webpack.
First, you can set up aliases per Amida's answer.
Also, you can set up an extra module root via resolve.modules to make webpack look into your src folder, when you are importing something absolute, like lib/utils.js

Import Highcharts and highcharts-more (AngularJS 1.5 + TypeScript + webpack)

I'm trying to use Highcharts with some of its extensions (like "highcharts-more") in a project that uses webpack, TypeScript and AngularJS (version 1.5).
I've installed Highcharts through npm (https://www.npmjs.com/package/highcharts), but I'm not able to import the extensions that come with it.
The actual trick I'm doing is to set some global variables in the webpack config file
plugins: [
new webpack.ProvidePlugin({
Highcharts: 'highcharts',
HighchartsMore: 'highcharts/highcharts-more',
HighchartsExporting: 'highcharts/modules/exporting'
})
]
and extending Highcharts manually
HighchartsMore(Highcharts);
HighchartsExporting(Highcharts);
without any import in between. With this non-ideal solution TypeScript is complaining because
error TS2304: Cannot find name 'HighchartsMore'
error TS2304: Cannot find name 'HighchartsExporting'
In particular with Highcharts there is no error. Which I guess has to do with the fact that Highcharts is the only thing I manage to import, via
import * as Highcharts from 'highcharts';
which I can substitute with the Highchart global declaration in the webpack config. What I would like is to import every module in a clean way, something like
import {HighchartsMore} from 'highcharts-more';
Any idea is very much appreciated.
This type of error can occur when you do not have definition files for exported variables. Those Highcharts extensions still require them - you might want to read more about importing modules without d.ts here: https://github.com/Urigo/meteor-static-templates/issues/9 - it might change in the future.
You need to create a d.ts file for the extensions. For highcharts-more this is my file:
/// <reference path="index.d.ts" />
declare var HighchartsMore: (H: HighchartsStatic) => HighchartsStatic;
declare module "highcharts/highcharts-more" {
export = HighchartsMore;
}
reference path points to standard DefinietelyTyped Highcharts file from here https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/highcharts/highcharts.d.ts
It allows to use type from Highcharts.d.ts because initializing will need proper typing for initializing extension:
HighchartsMore(Highcharts);
And finally don't forget to include all d.ts files by defining tsconfig or writing reference path in your files.
remove these lines from webpack.config.js:
plugins: [
new webpack.ProvidePlugin({
Highcharts: 'highcharts',
HighchartsMore: 'highcharts/highcharts-more',
HighchartsExporting: 'highcharts/modules/exporting'
})
]
install typings file for highcharts using this:
npm install --save #types/highcharts
change your import statements to following:
import * as Highcharts from 'highcharts';
import HighchartsMore = require('highcharts/highcharts-more');
HighchartsMore(Highcharts);

Resources