Next.js: pages/_app.js doesn't have getStaticProps

Created on 3 May 2020  路  12Comments  路  Source: vercel/next.js

Feature request

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)

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.

getStaticProps would be useful here, else I have to put this on every page individually, and pass props down

All 12 comments

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`);
Was this page helpful?
0 / 5 - 0 ratings

Related issues

jesselee34 picture jesselee34  路  3Comments

knipferrc picture knipferrc  路  3Comments

flybayer picture flybayer  路  3Comments

renatorib picture renatorib  路  3Comments

olifante picture olifante  路  3Comments