Next.js: pass additional props to the page during static export?

10,260

UPD Apr 4 20 At least in the next.js 9.3 there are getStaticProps and getStaticPaths

(complete example)

const IndexPage: NextPage<{ names: string[] }> = (props) => {
  return (
    <main>
      <section>
        {props.names.map((name) => (
          <div key={name}>
            <Link href={`/users/${name}`}>
              <a>{name}</a>
            </Link>
          </div>
        ))}
      </section>
    </main>
  );
};

export const getStaticProps: GetStaticProps = async () => {
  const data: User[] = readJsonSync("./data.json");

  return {
    props: {
      names: data.map((user) => user.name),
    },
  };
};

export default IndexPage;

UPD Dec 4 19

There is an RFC for getStaticProps which solves this: https://github.com/zeit/next.js/issues/9524


Here is what I ended up with.

_app.js:

import React from "react";
import App, { Container } from "next/app";

import fs from "fs";
import { resolve, join } from "path";

export default class extends App {
  static async getInitialProps({ Component, ctx }) {
    const { req, asPath } = ctx;
    let pageProps = {};

    if (Component.getInitialProps) {
      pageProps = await Component.getInitialProps(ctx);
    }

    let p;
    if (req) {
      p = JSON.parse(
        fs.readFileSync(resolve(join("data", asPath, "route.json"))).toString()
      );
    } else {
      p = await (await fetch(`/data${asPath}/route.json`)).json();
    }

    return { pageProps: { ...pageProps, ...p } };
  }

  render() {
    const { Component, pageProps } = this.props;
    return (
      <Container>
        <Component {...pageProps} />
      </Container>
    );
  }
}

in next.config.js:

const fetch = require("isomorphic-unfetch");
const fs = require("fs");
const path = require("path");
const fse = require("fs-extra");
const withBundleAnalyzer = require("@next/bundle-analyzer")({
  enabled: false
});

module.exports = withBundleAnalyzer({
  webpack(config) {
    config.node = { fs: "empty", path: "empty" };
    return config;
  },
  async exportPathMap() {
    const response = await fetch(
      "https://jsonplaceholder.typicode.com/posts?_page=1"
    );
    const postList = await response.json();
    fs.writeFileSync(
      path.resolve(`data/route.json`),
      JSON.stringify({ postList }, null, 2)
    );
    for (let i = 0; i < postList.length; ++i) {
      const id = postList[i].id;
      const response = await fetch(
        `https://jsonplaceholder.typicode.com/posts/${id}`
      );
      const post = await response.json();
      const fn = path.resolve(`data/post/${id}/route.json`);

      await fse.outputFile(fn, JSON.stringify(post, null, 2));
    }

    const pages = postList.reduce(
      (pages, post) =>
        Object.assign({}, pages, {
          [`/post/${post.id}`]: {
            page: "/post"
          }
        }),
      {}
    );

    return Object.assign({}, pages, {
      "/": { page: "/" }
    });
  }
});

Share:
10,260
Evgeny Timoshenko
Author by

Evgeny Timoshenko

JavaScript | Node.js Печатные материалы и игры для детей

Updated on June 27, 2022

Comments

  • Evgeny Timoshenko
    Evgeny Timoshenko almost 2 years

    I'm trying to statically export a next.js app. The docs says the page object has only 2 values: page and query. Is there a way to pass additional props to the page?

    I've tried to use query for this, but it seems that next's router is not aware of the route's query object. Hence it didn't work.

    In other words, I have a list of blog posts at build time, how could I inline them to the page (page component)?

    I guess react-static has a routeInfo.json which is prefetched for every route. I wonder if there is anything similar to it in next.js.

  • theLucre
    theLucre over 4 years
    This is awesome, thank you for sharing. I wanted a solution that only requested global data once during compile and never during client side routes. I used your file write from the exportPathMap callback to cache a request once during export and accessed the data client side using the __NEXT_DATA__ window global. See conversation here: spectrum.chat/next-js/general/…