I think _app.js also should have getStaticProps as Layout, Providers etc can use it's data.
(Having that _app.js has getInitialProps it will be good)
I was confused recently by this not being available. I thought it would be a convenient way to fetch data at build time.
Is there a better/ more idiomatic way for this?
I have a select menu inside my app header that I want to pre-populate with data at build.
I wrap all pages with this in _app.tsx.
getStaticProps would be useful here, else I have to put this on every page individually, and pass props down
@timneutkens thanks for hinting me to the right issue.
What about giving the implementation an 'private options object' which allows _app usage for getStaticProps? Or do you still plan to lift this restriction for both? And if yes when? Or can we help somehow?
My use case: I want to require automatically all redux's reducers from one directory at build-time (hence I need to read a directory on the server at build-time).
Any news on this, is the restriction going to be lifted?
My use case: Fetch Site meta data and navigation menus.
In the same situation as @sven-ra , are there any updates on this restriction being lifted?
In the same situation as @sven-ra , are there any updates on this restriction being lifted?
@sven-ra same situation.
It's like I'm having the same problem with fetching and pre populate data in _APP, in ex: I would verify if user is logged in every requisition otherwise I send him to login page, and in the login if they are actually have access token, it will be redirected to home. I'm finding this actually very hard to implement, or maybe I'm newby yet
Want this, too.
Hi all, take a look at my discussion post here and let me know if this proposal would solve your use case: https://github.com/vercel/next.js/discussions/18052
Hi, I have the same issue. I'd like to be able to compute the width and height of my static images at build time, and then use them to call new Image component with the right dimensions.
I'm using mdx, so I need to give a translation map in __app.ts to say how to interpret an image markdown tag. Here is what I'm looking to do:
// __app.ts
export default function MyApp({ Component, pageProps, imageDimensions }: AppProps) {
return (
<MDXProvider components={mdxComponents(imageDimensions)}>
<Layout>
<Component {...pageProps} />
</Layout>
</MDXProvider>
);
}
const mdxComponents = (imageDimensions: { [key: string]: Dimensions }) => {
img: ({ src }: { alt: string; src: string }) => {
const { width, height } = imageDimensions[src]; // imageDimensions is computed at build time with actual static dimensions of my images
return <Image src={src} width={dimensions.width} height={dimensions.height} />;
},
};
export async function getStaticProps() {
// ...
// logic to get image dimensions
// ...
return {
props: { imageDimensions },
};
}
Being able to use getStaticProps in __app.ts would be some great help. Otherwise, what's the idiomatic way of computing data at build time and use it in __app.ts?
Just reposting here the workaround I found for people that may need it.
So basically I use a script rename-images-with-size to transform all my image filenames from imageName.png into imageName.1200x800.png where 1200 is the width of imageName and 800 its height.
This allows me to use this information in with the new next/Image component and avoid Cumulative Shift Layout.
// __app.ts
...
const baseWidth = 680;
const mdxComponents = {
img: ({ src, alt }: { alt: string; src: string }) => {
const { unsized, ratio } = getImageDimensions(src);
return (
<>
<Image
className="Image"
src={src}
alt={alt}
unsized={unsized}
width={baseWidth}
height={baseWidth * ratio}
/>
<style jsx>
{`
:global(.Image) {
padding-bottom: 16px;
}
`}
</style>
</>
);
},
};
const getImageDimensions = (src: string) => {
const filenameParts = src.split(".");
if (filenameParts.length === 3) {
const dimensions = filenameParts[1];
const [width, height] = dimensions.split("x").map((l) => parseInt(l));
const ratio = height / width;
return {
width,
height,
ratio,
};
}
return { ratio: 1, unsized: true };
};
// rename-images-with-size.mjs
#!/usr/bin/env node
import glob from "glob-promise";
import sizeOf from "image-size";
import { promises as fs } from "fs";
const imageFilenames = await glob(
"public/*"
);
let renamedImages = 0;
imageFilenames.forEach((filename) => {
const filenameParts = filename.split(".");
if (filenameParts.length === 1) {
return; // directory
} else if (filenameParts.length > 3) {
throw new Error(`Invalid filename: ${filename}`);
}
const filePrefix = filenameParts[0];
const fileExtension = filenameParts.slice(-1)[0];
try {
const { width, height } = sizeOf(filename);
fs.rename(filename, `${filePrefix}.${width}x${height}.${fileExtension}`);
renamedImages++;
} catch (e) {
console.error(e);
}
});
console.log(`Renamed ${renamedImages} images`);
Most helpful comment
I have a select menu inside my app header that I want to pre-populate with data at build.
I wrap all pages with this in
_app.tsx.getStaticPropswould be useful here, else I have to put this on every page individually, and pass props down