Matt
Matt

Reputation: 117

Why can't I read a JSON file on Vercel when using Next.js SSR?

I have a barebones Next.js project consisting of three main files (listed below) where I'm trying to generate the index page with data from a JSON file. If I deploy the project to Vercel using getStaticProps, everything works properly.

However, when I deploy using getServerSideProps, the project builds but I get "500: Internal Server Error" when visiting the site and an error message (also listed below) in Vercel's Functions logs. I can run the app in development and deployment modes using getServerSideProps locally, just not on Vercel.

Why is the project able to find the JSON file when deployed to Vercel while using getStaticProps, but not getServerSideProps?

pages/index.tsx:

import { GetStaticProps, GetServerSideProps } from 'next';
import { User, getUsers } from '../lib/users';

// export const getStaticProps: GetStaticProps = async () => {
export const getServerSideProps: GetServerSideProps = async () => {
    const users = await getUsers();
    return { props: { users } };
};

export default function Home({ users }) {
    return (
        <div>
            {users.map((user: User) => (
                <p key={user.id}>{user.name}</p>
            ))}
        </div>
    );
}

lib/users.ts:

import fs from 'fs';

export interface User {
    id: number;
    name: string;
}

export function getUsers(): User[] {
    const users = JSON.parse(fs.readFileSync('data/users.json').toString());
    return users;
}

data/users.json:

[
    { "id": 1, "name": "Alice" },
    { "id": 2, "name": "Bob" },
    { "id": 3, "name": "Charlie" }
]

Vercel's Functions log:

[GET] /
09:41:25:73
2022-03-11T17:41:26.362Z    c8febc98-491a-4433-a2af-6dd7be25b040    ERROR   Error: ENOENT: no such file or directory, open 'data/users.json'
    at Object.openSync (fs.js:497:3)
    at Object.readFileSync (fs.js:393:35)
    at getUsers (/var/task/.next/server/pages/index.js:28:52)
    at getServerSideProps (/var/task/.next/server/pages/index.js:40:25)
    at Object.renderToHTML (/var/task/node_modules/next/dist/server/render.js:566:26)
    at processTicksAndRejections (internal/process/task_queues.js:95:5)
    at async doRender (/var/task/node_modules/next/dist/server/base-server.js:855:38)
    at async /var/task/node_modules/next/dist/server/base-server.js:950:28
    at async /var/task/node_modules/next/dist/server/response-cache.js:63:36 {
  errno: -2,
  syscall: 'open',
  path: 'data/users.json',
  page: '/'
}
RequestId: c8febc98-491a-4433-a2af-6dd7be25b040 Error: Runtime exited with error: exit status 1
Runtime.ExitError

Upvotes: 4

Views: 5086

Answers (3)

mamena tech
mamena tech

Reputation: 605

i hope this help to read file using process.cwd()

import fse from "fs-extra"
import path from "path"


 const filePath = path.join(process.cwd(), "firebaseServiceAccount.json")

     fse.readFile(filePath, 'utf-8', async (error, data) => {
     
      const jsonData = JSON.parse(data);

     })

Upvotes: 1

Paiman Rasoli
Paiman Rasoli

Reputation: 1214

This is another way of reading the JSON data on the server-side like getServerSideProps function.

  1. create a folder called data at the root of the project and put the JSON file in the directory.

  2. Then on the page where you have getServerSideProps you can import file like this.

    export async function getServerSideProps(){
      // path to the JSON file
      const staticData = await import('../../../data/index.json').then((res) => res.default);
      console.log("Json data" , staticData);
      return {
         props : {
            data : staticData || null
          }
       }
    }
    

Then check the console you should see the response as an object.

enter image description here

You can also do this like separate function like in the previous answer just make sure the file is in root not in public and change the function to async function.

export async function getUsers(): User[] {
 const users = await import('../data/index.json').then((res) => res.default);
   return users;
}

and in getServerSideProps just import the function and call it from there.

Upvotes: 0

Paiman Rasoli
Paiman Rasoli

Reputation: 1214

Make sure that data folder place in public folder.

public
 data
   user.json
pages
styles

and put a slash inside fs.readFileSync

export function getUsers(): User[] {
const users = JSON.parse(fs.readFileSync('/data/users.json').toString());
return users;
}

Your JSON must be like this:

{
"users" : [
  { "id": 1, "name": "Alice" },
  { "id": 2, "name": "Bob" },
 { "id": 3, "name": "Charlie" }
]
}

Upvotes: 3

Related Questions