Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[RFC]: Univerzal image component #8291

Open
1 task
vanam opened this issue May 11, 2023 · 9 comments
Open
1 task

[RFC]: Univerzal image component #8291

vanam opened this issue May 11, 2023 · 9 comments

Comments

@vanam
Copy link
Contributor

vanam commented May 11, 2023

Summary

A universal image component for generic way of dealing with images without worrying whether it is a PNG, JPEG or SVG, ideally with more features such as optimization, loaders etc.

    <Image
      src="/profile.png"
      width={500}
      height={500}
      alt="Picture of the author"
    />

Inspiration: https://nextjs.org/docs/app/building-your-application/optimizing/images

Motivation

When I experimented with RedwoodJS I tried to use a SVG logo. I went to the Assets and Files docs page. Copied an example and replaced "png" with "svg" and boom...it didn't work.

import logo from './logo.svg'

const Header = () => {
  return (
    <header>
      {/* ... */}
      <img src={logo} alt="Logo" />
    </header>
  )
}

export default Header

I did some research and discovered several pitfalls:

import { MetaTags } from '@redwoodjs/web'

import Favicon from '/public/favicon.png'
import Logo from '/public/logo.svg'
import LogoNoXml from '/public/logo-no-xml.svg'
import LogoSimple from '/public/logo-simple.svg'

const HomePage = () => {
  return (
    <>
      <MetaTags title="Home" description="Home page" />

      <h1>HomePage</h1>
      <main className="flex min-h-screen flex-row items-center justify-between p-24">
        <img
          src={Favicon}
          width={30}
          height={15}
        />

        <img
          src='/logo.svg'
          width={30}
          height={15}
        />
        {/* Unexpected token (1:1) */}
        {/* <Logo /> */}
        <img
          src='/logo-no-xml.svg'
          width={30}
          height={15}
        />
        {/* name.name.toLowerCase is not a function */}
        {/* <LogoNoXml /> */}
        <img
          src='/logo-simple.svg'
          width={30}
          height={15}
        />
        {/* Type 'FC<SVGProps<SVGSVGElement>>' is not assignable to type 'string' */}
        {/* index.d.ts(2203, 9): The expected type comes from property 'src' which is declared here on type 'DetailedHTMLProps<ImgHTMLAttributes<HTMLImageElement>, HTMLImageElement>' */}
        <img
          src={LogoSimple}
          width={30}
          height={15}
        />
        <LogoSimple />
    </main>
    </>
  )
}

export default HomePage

SVGs are very fragile.

Standard SVG with <?xml> tag

import Logo from '/public/logo.svg'

fails with Unexpected token (1:1). Cannot inline SVG with <?xml tag.

SVG without <?xml> tag

import Logo from '/public/logo-no-xml.svg'

is the same logo but without the <?xml tag and it fails with name.name.toLowerCase is not a function . I guess it has some issue with the complexity of the SVG file.

Simple SVG

import Logo from '/public/logo-simple.svg'

is the simple logo and it works.

Of course, I can always just use plain ol' <img>

<img
          src='/logo.svg'
          width={30}
          height={15}
        />

Detailed proposal

I propose having an <Image> component which gives me single API when dealing with images.

Minimal version

Support for imported images or path.

import logo from '@/public/logo.svg'

...
      <Image
        src="/logo.svg"
        alt="logo"
      />
      <Image
        src={logo}
        alt="logo"
      />

Advanced features

Inspiration from Next.js

Are you interested in working on this?

  • I'm interested in working on this
@dthyresson
Copy link
Contributor

Might a RedwoodJS version of https://github.com/ascorbic/unpic-img work?

@thedavidprice
Copy link
Contributor

thedavidprice commented May 14, 2023

@vanam I can't stop thinking about this idea since you posted. Do you have experience with building components like this? Is there interest and/or availability on your end with helping work on this in some capacity?

@vanam
Copy link
Contributor Author

vanam commented May 16, 2023

I would love to participate, however, I am a backend developer (Java/PHP) with almost no experience with Typescript/React. I am currently at a level where I mostly copy&paste code from tutorials as I am rapid prototyping a tiny app :( Sorry

@dthyresson
Copy link
Contributor

@vanam Could you try out just the React version of https://unpic.pics/img/react/ and see if those features match what you're looking for?

If so, perhaps can contribute a Redwood version or add the React version to the @redwoodjs/web package as an image component.

@dthyresson
Copy link
Contributor

dthyresson commented May 16, 2023

Also, @vanam please see the docs regarding svg's here: https://redwoodjs.com/docs/prerender#images-and-assets

re-exporting the SVG as a component requires a small change

image

@vanam
Copy link
Contributor Author

vanam commented May 18, 2023

Also, @vanam please see the docs regarding svg's here: https://redwoodjs.com/docs/prerender#images-and-assets

re-exporting the SVG as a component requires a small change

image

I tried that (https://github.com/vanam/svg-demo/blob/master/redwoodjs/web/src/components/LogoComponent/LogoComponent.tsx) but the result is the same. It seems to struggle with XML header and some other XML features when using svg's react component.

I also looked at https://unpic.pics/img/react/ and it has a fallback to regular <img src="logo.svg"> when not using a CDN. And I also cannot feed it with React.FC<React.SVGProps<SVGSVGElement>>. It is very nice library, though.

I understand why one cannot just place XML header at random place in DOM. I would love the image to be transformed so it can be safely used as a react component. That is just layman opinion. Might be too much work for little benefit, though.

The more I think about, the more I think I want to spoil myself. It would need some preprocessing of an image. I guess just a warning in docs would be enough to keep me from going down this rabbit hole. I can just avoid inlining SVGs without cleaning them up first.

@dthyresson
Copy link
Contributor

You may want to look at https://imagekit.io and https://imgix.com as they offer CDN hosting for speedy image retrieval and caching and lots of transformations.

Supabase storage also has some transforms (and more will come): https://supabase.com/docs/guides/storage/image-transformations

@pantheredeye
Copy link
Collaborator

@dthyresson @vanam I am curious, after following along somewhat, is this issue and proposed solution still valid for RW, should it be enhanced, or should it be closed?

@Benjamin-Lee
Copy link
Contributor

Just adding that I was looking for exactly this to use on the landing page of my build competition submission. My ideal API would be the same as Next's. I don't want to set up an image CDN to get decent performance on my landing page. For now, I'll just manually create a webp and fall back to that but I would love to see some DX improvements here.

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

No branches or pull requests

5 participants