When comparing the use of fs
with import
/require
, it seems that if you want to avoid rebuilding each time a file changes, opting for fs
would be more suitable.
To abstract this behavior, creating a function based on the example provided at https://vercel.com/guides/loading-static-file-nextjs-api-route could be beneficial.
import { promises as fs } from 'fs';
export default async function Page() {
const file = await fs.readFile(process.cwd() + '/app/data.json', 'utf8');
const data = JSON.parse(file);
return (
<div>
<h1>{data.title}</h1>
<p>{data.content}</p>
</div>
);
}
In any part of your code, you can define
const myReadFile = async (path: string) => {
const file = await fs.readFile(process.cwd() + path, "utf8");
const data = JSON.parse(file);
return data;
};
And then call this function in any component
export default async function Page() {
const data = myReadFile("/app/data.json");
return (
<div>
<h1>{data.title}</h1>
<p>{data.content}</p>
</div>
);
}
While you may not save much character-wise, reusability is always advantageous to prevent repetitive tasks, and in this scenario, there are likely no downsides.
You have the flexibility to extend the function as needed - adding types for parsing or other customizations.
const myReadFileTyped = async <T,>(path: string): Promise<T> => {
const file = await fs.readFile(process.cwd() + path, "utf8");
const data: T = JSON.parse(file);
return data;
};
For instance,
type Data = {title:string, content:string};
const data = await myReadFileTyped<Data>("/app/data.json")
and utilize the retrieved data in your component.
If error handling is required, you can implement a safe version of the function that returns null
on exceptions:
const myReadFileSafe = async <T,>(path: string): Promise<T | null> => {
try {
const file = await fs.readFile(process.cwd() + path, "utf8");
const data: T = JSON.parse(file);
return data;
} catch (e) {
console.log(e);
return null;
}
};
Subsequently,
export default async function Page() {
const data = await myReadFileSafe("/app/data.json");
if (data === null) {
return null;
}
return (
<div>
<h1>{data.title}</h1>
<p>{data.content}</p>
</div>
);
}
This approach allows for further customization and integration of validation processes, leveraging external libraries if necessary.