Skip to content
This repository has been archived by the owner on Nov 16, 2023. It is now read-only.

import images #12

Open
StokeMasterJack opened this issue May 14, 2017 · 25 comments
Open

import images #12

StokeMasterJack opened this issue May 14, 2017 · 25 comments

Comments

@StokeMasterJack
Copy link

This works with stock create-react-app:

import logo from "./ss-logo-transparent.png";

@Javier-Rotelli
Copy link

This may be related:
https://stackoverflow.com/a/36151803/1064584
C&P the answer:

The problem is that you confuse TypeScript level modules and Webpack level modules.
In Webpack any file that you import goes through some build pipeline.
In Typescript only .ts and .js files are relevant and if you try to import x from file.png TypeScript just does not know what to do with it, webpack config is not used by TypeScript.
In your case you need to separate the concerns, use import from for TypeScript/EcmaScript code and use require for Webpack specifics.
You would need to make Typescipt ignore this special Webpack require syntax with a definition like this in a .d.ts file:
declare function require(string): string;
This will make Typescript ignore the require statements and Webpack will be able to process it in the build pipeline.

@pelotom
Copy link

pelotom commented Aug 31, 2017

All you have to do is add

declare module '*.png'

to a .d.ts file included in your build, and you can use the regular import syntax, no need for require.

@MrDesjardins
Copy link

There is two things that must be done. The first one got identified by pelotom which is to specify to TypeScript how to handle the PNG file. However, the original post contains a syntax that was not working for me. I had to use the star/import syntax.

To summarize
1: Create a file with : declare module '*.png'
2 Import with *: import * as logo from "./ss-logo-transparent.png";

@midori0507
Copy link

midori0507 commented Sep 8, 2017

Type '{ src: typeof "*.png"; alt: "logo"; }' is not assignable to type 'HTMLProps<HTMLImageElement>'. Types of property 'src' are incompatible. Type 'typeof "*.png"' is not assignable to type 'string | undefined'. Type 'typeof "*.png"' is not assignable to type 'string'.

Even i tried to export default as string still not satisfy it

@MrDesjardins
Copy link

@midori0507 How are you passing the src to your image?

It should be similar to :

import * as logo from "./logo.png";
<img src={logo}  /> 

@stunaz
Copy link

stunaz commented Nov 2, 2017

Having :
1:

declare module "*.png" {
  const content: string;
  export default content;
}

2: Import with *: import * as logo from "./ss-logo-transparent.png";
3:

import * as logo from "./logo.png";
<img src={logo}  />

4: I sill get Type 'typeof "*.png"' is not assignable to type 'string'.

@pelotom
Copy link

pelotom commented Nov 2, 2017

stunaz: the way you have it declared is as a default export only, so you would need to use it as

import logo from "./logo.png";

@stunaz
Copy link

stunaz commented Nov 2, 2017

@pelotom spoke too soon, not working like that. I got undefined. With * as , I have my path to the image. but the typescript is complaining as shown above
Does the loader matters? Right now I am using url-loader

@stunaz
Copy link

stunaz commented Nov 2, 2017

ok got rid of typescript warning by removing

{
  const content: string;
  export default content;
}

Just having declare module '*.png' works

@ghost
Copy link

ghost commented Feb 21, 2018

I tried everything but it is not working. Is it because of my loaders?

const sharedConfig = () => ({
    stats: { modules: false },
    resolve: { extensions: ['.js', '.jsx', '.ts', '.tsx'] },
    output: {
        filename: '[name].js',
        publicPath: 'dist/' // Webpack dev middleware, if enabled, handles requests for this URL prefix
    },
    module: {
        rules: [
            { test: /\.tsx?$/, include: /ClientApp/, use: 'awesome-typescript-loader?silent=true' },
            { test: /\.(png|jpg|jpeg|gif|svg)$/, use: 'url-loader?limit=25000' }
        ]
    },
    plugins: [new CheckerPlugin()]
});

@peterwang-s
Copy link

I've fixed this problem in this way:

declare module "*.png" {
    const value: any;
    export = value;
}
/// <reference path='./index.d.ts'/>

import  * as logoImg from "../../assets/images/logo.png";

<img src={logoImg} />

@damiangreen
Copy link

Thanks @pelotom
This seems like black magic to me.. Is there any explanation anywhere of why this works?

@justinwaite
Copy link

@pelotom or @damiangreen
My problem is that the image files do not get copied over to the outdir. What setup are you using to ensure that those images exist in the outdir?

@justinwaite
Copy link

I created an answer on SO outlining a couple of options: https://stackoverflow.com/a/49715468/4216035

@andrewMuntyan
Copy link

andrewMuntyan commented Apr 14, 2018

Do not work for me. Have i missed something? Have i messed up with folders structure/absolute|relative paths?
I've added import-jpg.d.ts and do not have ts-loader errors, but still can't import image. But i don't have any issues with using same image in css as background-image (i have css modules).
in case when i use const image = require('./large-image.jpg') it works just fine.

webpack does see this particular image during build process

Built at: 4/14/2018 5:43:07 PM
                               Asset       Size  Chunks             Chunk Names
d2281ac61e357b25714ab2a6d357291e.jpg    947 KiB          [emitted]
                      main.bundle.js   2.82 MiB    main  [emitted]  main
                          index.html  178 bytes          [emitted]
Entrypoint main = main.bundle.js
import image from './large-image.jpg';

console.log('----------');
console.log('image');
console.log(image); //undefined here
console.log('----------');

export default class CssModules extends React.Component<{}, {}> {
  render() {
    return (
      <section className={styles.root}>
        <div className={styles.largeImageBg} />
        <img className={styles.largeImageImage} src={image} alt="" />
      </section>
    );
  }
}

i'm using webpack-url-loader and have next project structure:

project
|- /config
  |- /webpack
    |- common.webpack.config.js
  |- tsconfig.json

|- /src
  |- /components
    |- /component
      |- styles.css
      |- index.tsx
      |- large-image.jpg

|- /typings
  |- import-jpg.d.ts

here is the gist with files content

@andrewMuntyan
Copy link

andrewMuntyan commented Apr 15, 2018

solved:
desired options is "esModuleInterop": true

i use "typescript": "^2.8.1"

i think i found reason of issue
when i use

declare module '*.jpg' {
  const fileName: string;
  export default fileName;
}

and then

import image from './large-image.jpg';

i get next picture in my compiled code
2018-04-15_1402
it is compiled to

var large_image_jpg_1 = __webpack_require__(4);
console.log(large_image_jpg_1.default);

large_image_jpg_1 becomes string - image url.
and string.default is undefined
but if i use

declare module '*.jpg' {
  const fileName: string;
  export = fileName;
}

and then

import * as image from './large-image.jpg';

it works fine.

i've seen this issue, but allowSyntheticDefaultImports did not help.

any thoughts?

@TomasHubelbauer
Copy link

TomasHubelbauer commented Apr 28, 2018

For anyone using Parcel, this works:

  1. index.d.ts: declare module '*.png'; (no need for the content or value fun)
  2. index.tsx: /// <reference path='./index.d.ts'/> (props to @redredredredredred)
  3. index.tsx: import logo from "./logo.png"; (no need for *)
  4. <img src={logo} /> or <div style={``background: url(${logo});``}>…</div> (dunno how to escape backticks in inline code)

@Elijen
Copy link

Elijen commented Jun 20, 2018

One problem I am having with the approach @pelotom suggested is that TypeScript will not check if the file imported actually exists.

import image from '../this/path/is/wrong.jpg'; will not fail on compile, but will cause a crash on runtime. Is there any workaround for this?

For some reason tsc only checks the path in require('../wrong/file.jpg') if the file is .js (not .ts).

@velipso
Copy link

velipso commented Jul 31, 2018

the following worked for me:

  1. use "module": "commonjs" inside tsconfig.json (get access to older libraries)
  2. use declare module '*.png'; in typings.d.ts
  3. use import image = require('./the/image.png');
  4. use <img src={image} />

@thecodecafe
Copy link

@pelotom @midori0507 @redredredredredred

So....
Does this code snippet

declare module "*.png" {
    const value: any;
    export = value;
}

Have a file it's meant to be in and a location for that file?

thanks.

@ww-k
Copy link

ww-k commented Sep 28, 2018

I've fixed this problem in this way:

declare module "*.png" {
    const value: any;
    export = value;
}
/// <reference path='./index.d.ts'/>

import  * as logoImg from "../../assets/images/logo.png";

<img src={logoImg} />

this work for me.

But add /// <reference path='...'/> in every ts file is ugly.
Is there a pretty way ?
I had tried add typeRoots in tsconfig.json, and it's not work.

project architecture

|- /src
  |- /components
    |- /component
      |- index.less
      |- index.tsx
      |- large-image.jpg

|- /typings
  |- index.d.ts

|- tsconfig.json

tsconfig.json

{
    "compilerOptions": {
        "outDir": "./ts_built",
        "typeRoots": [
            "./node_modules/@types",
            "./typings"
        ],
        "sourceMap": true,
        "noImplicitAny": false,
        "allowJs": true,
        "moduleResolution": "node",
        "module": "commonjs",
        "target": "es2015",
        "jsx": "react",
    },
    "include": [
        "./src/**/*"
    ]
}

typings/index.d.ts

// declare webpack modules
declare module '*.png'
declare module '*.jpg'
declare module '*.gif'
declare module '*.less'

@kabua
Copy link

kabua commented Oct 9, 2018

@ww-k I had the same question. Here's what worked for me. Inside your tsconfig.json file add the following:

  "includes" :[
    "./typings/**/*.d.ts"
  ],

@ww-k
Copy link

ww-k commented Oct 10, 2018

@kabua thank you. It seems like include config prevent ts load .d.ts files which in compilerOptions.typeRoots and not in include

@AnshulBasia
Copy link

All you have to do is add

declare module '*.png'

to a .d.ts file included in your build, and you can use the regular import syntax, no need for require.

I have too many ".d.ts" files in my project. Which one to use ?

@jerrygreen
Copy link

@AnshulBasia pretty much any of it. But better some root .d.ts like globals.d.ts

Btw, how did I solve it:

  1. Added this to my globals.d.ts
declare module '*.png' {
  const content: string
  export default content
}
  1. Added this to my tsconfig.json
`{ "compilerOptions": { "esModuleInterop": true } }`

So imports like this works perfectly:

import image from './my_image.png'

P.S. I feel like this is still just a workaround, these png/etc files should be supported out of the box

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests