Nextjs: Unable to load images from static folder - reactjs

How can I load images in a component in Next.js? Do I have to build the project first? If yes, is there a way to load the images without building first? I cannot get this to work, no matter what I try.

from the docs:
Next.js can serve static files, like images, under a folder called
public in the root directory. Files inside public can then be
referenced by your code starting from the base URL (/).
So, first add an image to public/my-image.png and then you can reference it:
<img src="/my-image.png" />
I think next.js will have a watch on this directory so you won't need to restart your server every time you put something in there.

The static directory has been deprecated. Place files in public/static directory

Another way I find out Next Images
installation:
npm install --save next-images
or
yarn add next-images
Usage:
Create a next.config.js in your project
// next.config.js
const withImages = require('next-images')
module.exports = withImages()
Optionally you can add your custom Next.js configuration as parameter
// next.config.js
const withImages = require('next-images')
module.exports = withImages({
webpack(config, options) {
return config
}
})
And in your components or pages simply import your images:
export default () => <div>
<img src={require('./my-image.jpg')} />
</div>
or
import myImg from './my-image.jpg'
export default () => <div>
<img src={myImg} />
</div>

From Next.js v11 onwards, one can now directly import images without any additional config or dependencies. Official example (comment mine):
import Image from 'next/image'
import profilePic from '../public/me.png'
function Home() {
return (
<>
<h1>My Homepage</h1>
<Image src={profilePic} alt="Picture of the author" />
{/* <img src={profilePic.src} alt="Picture of the author" /> */}
<p>Welcome to my homepage!</p>
</>
)
}
export default Home
Docs: next/image

With Next 10+
To serve an optimized image:
import Image from 'next/image'
<Image src={'banner.jpg'} alt='Home Page' width={100} height={100} />
Place the image in the public folder. All the referenced images must be present in the public folder at the build time. Image hot deployment will not work for images that reside in the public folder.
You also can refer to cross-domain images with <Image> tag.
<Image src={'https://www.example.com/banner.jpg'} alt='Home Page' width={100} height={100} />
To allow cross-domain images, ensure to add the below entry to your next.config.js
module.exports = {
images: {
domains: ['www.example.com'],
},
}

what i like to do for directing to images is using environment variables. in next.js they are easily set in next.config.js file like below:
// next.config.js
module.exports = {
env: {
PUBLIC_URL: '/',
}
};
then you can direct to your publics path wherever it is by using process.env.PUBLIC_URL like below:
<img src={`${process.env.PUBLIC_URL}/my-image.jpg`} />
the advantages of using PUBLIC_URL environment variable over hard coding the path is that you can use another path for when file arrangements change (like in server). for then you could set conditionally which PUBLIC_URL value to use in production and development.
update
sometimes the problem of images used with next/Image not showing is bc of not setting the right layout value or it lacks width and height attributes when used with layout other than fill.
Using Image component of Next.js version 13 is a little bit different than than its previous versions. It's actually easier and you can use optimization features with less effort and work arounds. In this version :
you're not obligated to set domains in next.config.js.
you can either set the image its width and height or set to fill and handle its sizing with styles or classNames which means you can set max-height or max-width. so in that case that you don't know your image's width and height it's be shown properly.
as well as its previous versions you can use priority and ...

I will add here one obvious case, that is usually easily forgotten. It keeps appearing when one re-structure a site page and our IDE "silently fails" to update the paths of a related file/component or simply when one is more tired or distracted.
If you are using a page inside a folder
ex: mysiteDomain/pagefolder/page
You should be careful when using relative path.
Something like <img src="logo.png" /> should be changed it to <img src="../logo.png" /> since the compiled page will also be inside a folder pagefolder.
The path in the src attribute will be relative to the compiled page.
As an alternative, you could simply use an absolute path like for ex <img src="/logo.png" />. The path in the src attribute will be relative to the compiled root of the site.

Do NOT put public into /src!
In my case, I had a src dir into which I put my pages etc., which is an option described here. But I ALSO accidentally moved the public dir there. This will mess nextjs up -- you need to keep public in the root dir.

After running next build && next export and your images are not visible do this:
// next.config.js
/** #type {import('next').NextConfig} */
module.exports = {
reactStrictMode: true,
images: {
loader: "custom",
loaderFile: "./imageLoader.js",
},
assetPrefix: "./",
env: {
// dev does not need static path
ROOTDIR: process.env.NODE_ENV === "development" ? "" : "file:///C:/Users/.../out",
},
};
Create an imageLoader.js too in the root project
export default function imageLoader({ src, width, quality }) {
return `process.env.NODE_ENV === "development" ? "" : "file:///C:/Users/.../out${src}?w=${width}?q=${quality || 75}`;
}
Where file:///C:/Users/.../out refers to full path to the root of your build
Now you can append process.env.ROOT before "/*"

Related

react-leaflet custom marker icon in NextJS [duplicate]

I have a React component that's being used in Next.js page:
/pages/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import Layout from "../src/hoc/Layout/Layout";
import Main from "../src/components/Main/Main";
const Index = () => (
<Layout>
<Main />
</Layout>
);
export default Index
In Main.js I have the following code
import macbookIphone from '../../assets/images/mac-iphone.jpg';
I get the following error
Module parse failed: Unexpected character '�' (1:0) You may need an
appropriate loader to handle this file type, currently no loaders are
configured to process this file. See
https://webpack.js.org/concepts#loaders (Source code omitted for this
binary file)
I tried doing the following
In next-config.js
const withImages = require('next-images')
module.exports = withImages()
I'm still getting the same error.
What am I doing wrong?
/public/favicon/mail.png
=> "/favicon/mail.png" will work
From Next.js v11 onwards, you can do what you were doing without any additional config:
import macbookIphone from '../../assets/images/mac-iphone.jpg';
<Image src={macbookIphone} />
// or
<img src={macbookIphone.src} />
Ref: next/image
For earlier versions if you wish to import images instead of putting them in public directory, then you can configure file-loader or url-loader.
Please see
https://nextjs.org/docs/basic-features/static-file-serving
Next.js can serve static files, like images, under a folder called public in the root directory. Files inside public can then be referenced by your code starting from the base URL (/).
At least in our project, we use require for images instead of import. Our next config looks similar to yours.
Try the following and see if it helps:
const macbookIphone = require('../../assets/images/mac-iphone.jpg');
You can then use your image as the src like this:
<img src={macbookIphone}/>
Using images in Next.js is a bit different:
All your static assets like images must be placed in the public directory.
If your code is under src directory, i.e <app-name>/src/pages , <app-name>/src/components, ... then your public folder must be outside of the src directory. Public folder cannot be under src as <app-name>/src/public.
In this case your public directory must be under <app-name>/public.
If your code is not under src directory, i.e <app-name>/pages, <app-name>/components, ... then your public directory should be under <app-name>/public
Once you have that sorted, directly refer to the file in the <Image /> component provided by next/image as:
import Image from "next/image"
<Image src="/sample-image.png" width="64" height="64" />
or
import Image from "next/image"
import sampleImage from "<file-path>"
<Image src={sampleImage} width="64" height="64" />
provided you have a file under public/sample-image.png
If you have an image URL, directly provide it to the 'src' prop.
Find descriptive examples related to layouts at: https://github.com/vercel/next.js/tree/canary/examples/image-component
References:
https://nextjs.org/docs/basic-features/static-file-serving
https://nextjs.org/docs/api-reference/next/image
https://nextjs.org/docs/basic-features/image-optimization
https://nextjs.org/docs/advanced-features/src-directory
You can import images by using next-images
Step 1
npm install --save next-images
or
yarn add next-images
Step 2
// Create next.config.js
const withImages = require('next-images')
module.exports = withImages()
For Typescript
// Add following line in next-env.d.ts
/// <reference types="next-images" />
Restart your server and now you can import your images like
import img1 from "assets/images/cover_images/blog_1.png"
https://github.com/twopluszero/next-images
it worked for me like this, but putting the file in the public folder:
<Image width={150} height={100} src={'/punkieslogo.png'} alt="Picture of the author" />
you cannot access images in Next.js like in React.js unless they are stored in 'public' folder.

How to display images from object?

How to display image from object?
I was trying to copy relative path, but it's not working for me. Output on browser:
./images/avatars/image-maxblagun.png
data.json
"image": {
"png": "./images/avatars/image-amyrobson.png",
comment.tsx
import React from 'react';
import data from '../../data.json';
const Comment = () => {
const mapData = Object.values(data.comments).map((value) => (
<div key={value.id}>
<div>
<img src={value.user.image.png} alt={value.user.image.png} />
{value.content}
</div>
</div>
));
return <>{mapData}</>;
};
export default Comment;
Link to repository: https://github.com/xflameyoke/interactive-comment-section-app
To add to jsecksn's answer, usually you would import images and the like at the top of your file like this. This ensures that when your project is built, webpack will copy the necessary resources etc.
Since your requirement does not allow for such an import, I believe that just copying the resources to the public folder and changing the url's from relative to absolute is the easiest approach.
In that way the images are out of scope for data.json while rendering.
You must move your images folder images/avatars/ to the root of the /public folder in your project.
Meanwhile in data.json, modify the locations for each image, as if it (data.json) were inside the /public folder i.e. "png": "/images/avatars/image-juliusomo.png" and so forth.

Getting "Unsafe attempt to load URL data:image/svg+xml..." in Safari using a through React component

I'm using rollup to bundle a react npm package that contains an icon component that takes a name as a prop and returns an Icon with that name wrapped by a react component.
This is the component code:
import sprite from './public/sprite.svg';
function Icon({ name }) {
return <svg className="svg-wrapper">
<use href={`${sprite}#${name}`} />
</svg>
);
}
The folder structure is the following:
- src
- - public
- - - sprite.svg
- - icons
- - - some-icon.svg
- - - some-other-icon.svg
- - index.tsx # component with the code mentioned above
And this is my rollup config:
export default {
plugins: [
esbuild({
sourceMap: false,
target: "esnext"
}),
image(),
svgicons({
inputFolder: "src/icons",
output: "public/sprite.svg"
}),
json()
]
}
This works fine in Chrome (although it does inline all the svg inside of the href which I think it's the purpose of this approach) but in Safari it triggers the following error:
Unsafe attempt to load URL data:image/svg+xml,%3c%3fxm ....
Domains, protocols and ports must match.
The thing is, as mentioned, this is an npm package that packages the icons as part of the js bundle (inlining) so there's not much control over how this component is served since this is handled by the browser caching (also one of the key points of using this approach). I'm quite familiar with CORS and I know that perhaps avoiding to use data:image/svg+xml uri links would fix this but would increase the complexity of the build steps of this package (needing to build the icons using svgr/svgo and then have some kind of lookup table to give back the right icon based on the name prop i.e.).
So, ultimately my question is, with the sprite approach in a react component library is there a foolproof way of avoiding these kind of issues and cross-browser inconsistencies?
Thanks in advance for any help provided.
I have been struggling with this issue for a while. I guess this is a bug on Safari throwing an error because is dealing with a dataURI as if it was an external URL.
About your code, you could expose your sprite in a public folder or publish it in a cdn (good for caching purposes) and change the way rollup is handling your svg (it seems it is packing your svg as a dataURI). Alternatively, I implemented a workaround to convert the dataURI in a blob.
import sprite from './public/sprite.svg';
function dataURItoBlobUrl(dataURI: string) {
const svg = decodeURI(dataURI).split(',')[1];
const blob = new Blob([svg], { type: "image/svg+xml" });
return URL.createObjectURL(blob);
}
const blobUrl = dataURItoBlobUrl(sprite);
export const Icon: FC<IconProps> = ({ name, ...props }) => {
return (
<svg xmlns="http://www.w3.org/2000/svg" {...props}>
<use href={`${blobUrl}#${name}`}></use>
</svg>
);
};

Loading a local image with Gatsby [duplicate]

How to show images? It can not be shown correctly below.
In the src/components/Header.js file:
<img src="../images/logo.png" style={{width:"112",height:"28"}} />
Importing Assets Directly Into Files
import React from "react"
import logo from "./logo.png" // Tell Webpack this JS file uses this image
console.log(logo) // /logo.84287d09.png
function Header() {
// Import result is the URL of your image
return <img src={logo} alt="Logo" />
}
export default Header
The reason this is best is that it enables optimizations through the Webpack bundling pipeline, e.g. compression, data URLs, cache busting filename hashes, etc.
Using the Static folder
This is mostly useful for files other than images.
You can create a folder named static at the root of your project.
Every file you put into that folder will be copied into the public
folder. E.g. if you add a file named sun.jpg to the static folder,
it’ll be copied to public/sun.jpg
You can reference assets from the static folder in your code without
anything special required:
render() {
// Note: this is an escape hatch and should be used sparingly!
// Normally we recommend using `import` for getting asset URLs
// as described in the “Importing Assets Directly Into Files” page.
return <img src={'logo.png'} alt="Logo" />;
}
Corey's answer quotes the "Add custom webpack config" section of the Gatsby documentation, which is useful but unnecessary to load images.
Create a gatsby-node.js file at the root of your project if you don't already have one and add this:
const path = require("path")
exports.onCreateWebpackConfig = ({ stage, actions }) => {
actions.setWebpackConfig({
resolve: {
modules: [path.resolve(__dirname, "src"), "node_modules"],
alias: { react: path.resolve("./node_modules/react") },
},
})
}
This does two things:
It will make src the base for your imports
It will ensure that you don't run into weird bugs due to multiple versions of React getting loaded (plugins that need to reference React can cause this).
In your Header.js file, you can now do this:
import logo from "images/logo.png"
export const Header =>
<header>
<img src={logo} alt="Logo Alt Text" />
</header>
The rendered result of this will actually be different depending on the file size of your logo. If it's small enough, Gatsby will inline it using base64, reducing the number of HTTP requests required to load your page. If it's larger, it will be given an asset fingerprint and added to the assets available when your site is built and the URL to the file will be used for the src attribute (e.g. /images/logo-123asd.png). This will allow you to use HTTP cache headers that tell the browser it's safe to cache this file for a long time; if it changes, the URL will change and you don't need to worry about invalidating the cached version.

How to show images in a GatsbyJS project?

How to show images? It can not be shown correctly below.
In the src/components/Header.js file:
<img src="../images/logo.png" style={{width:"112",height:"28"}} />
Importing Assets Directly Into Files
import React from "react"
import logo from "./logo.png" // Tell Webpack this JS file uses this image
console.log(logo) // /logo.84287d09.png
function Header() {
// Import result is the URL of your image
return <img src={logo} alt="Logo" />
}
export default Header
The reason this is best is that it enables optimizations through the Webpack bundling pipeline, e.g. compression, data URLs, cache busting filename hashes, etc.
Using the Static folder
This is mostly useful for files other than images.
You can create a folder named static at the root of your project.
Every file you put into that folder will be copied into the public
folder. E.g. if you add a file named sun.jpg to the static folder,
it’ll be copied to public/sun.jpg
You can reference assets from the static folder in your code without
anything special required:
render() {
// Note: this is an escape hatch and should be used sparingly!
// Normally we recommend using `import` for getting asset URLs
// as described in the “Importing Assets Directly Into Files” page.
return <img src={'logo.png'} alt="Logo" />;
}
Corey's answer quotes the "Add custom webpack config" section of the Gatsby documentation, which is useful but unnecessary to load images.
Create a gatsby-node.js file at the root of your project if you don't already have one and add this:
const path = require("path")
exports.onCreateWebpackConfig = ({ stage, actions }) => {
actions.setWebpackConfig({
resolve: {
modules: [path.resolve(__dirname, "src"), "node_modules"],
alias: { react: path.resolve("./node_modules/react") },
},
})
}
This does two things:
It will make src the base for your imports
It will ensure that you don't run into weird bugs due to multiple versions of React getting loaded (plugins that need to reference React can cause this).
In your Header.js file, you can now do this:
import logo from "images/logo.png"
export const Header =>
<header>
<img src={logo} alt="Logo Alt Text" />
</header>
The rendered result of this will actually be different depending on the file size of your logo. If it's small enough, Gatsby will inline it using base64, reducing the number of HTTP requests required to load your page. If it's larger, it will be given an asset fingerprint and added to the assets available when your site is built and the URL to the file will be used for the src attribute (e.g. /images/logo-123asd.png). This will allow you to use HTTP cache headers that tell the browser it's safe to cache this file for a long time; if it changes, the URL will change and you don't need to worry about invalidating the cached version.

Resources