Can't resolve 'fs'
Answered
Indian Spitz posted this in #help-forum
Indian SpitzOP
Hello.
I would like to use Next static export and run the following code:
"use client";
import ProductPageLayout from "@/app/components/PageLayout/ProductPageLayout";
import { ProductOverview } from "@/app/components/Product/ProductOverview/ProductOverview";
import ReduxProvider from "@/app/store/ReduxProvider";
import { ProductPath } from "@/global/consts";
import readProductDataForCategory from "@/lib/api/readProductDataForCategory";
import { sortEntitiesByRank } from "@/utils/sortEntitiesByRank";
export default function Schliesszylinder({ productData }) {
return (
<ReduxProvider>
<ProductPageLayout>
<ProductOverview productData={productData} />
</ProductPageLayout>
</ReduxProvider>
);
}
export const getInitialProps = async () => {
const productData: any = await readProductDataForCategory(
ProductPath.Schliesszylinder
);
return {
props: {
productData: sortEntitiesByRank(productData),
},
};
};
And get the error:
./lib/api/readProductDataForCategory.ts:1:0
Module not found: Can't resolve 'fs'
3 |
4 | const readProductDataForCategory = async (dir: string) => {
https://nextjs.org/docs/messages/module-not-found
Import trace for requested module:
./app/schliesszylinder/page.tsx
What is the problem with it?
I would like to use Next static export and run the following code:
"use client";
import ProductPageLayout from "@/app/components/PageLayout/ProductPageLayout";
import { ProductOverview } from "@/app/components/Product/ProductOverview/ProductOverview";
import ReduxProvider from "@/app/store/ReduxProvider";
import { ProductPath } from "@/global/consts";
import readProductDataForCategory from "@/lib/api/readProductDataForCategory";
import { sortEntitiesByRank } from "@/utils/sortEntitiesByRank";
export default function Schliesszylinder({ productData }) {
return (
<ReduxProvider>
<ProductPageLayout>
<ProductOverview productData={productData} />
</ProductPageLayout>
</ReduxProvider>
);
}
export const getInitialProps = async () => {
const productData: any = await readProductDataForCategory(
ProductPath.Schliesszylinder
);
return {
props: {
productData: sortEntitiesByRank(productData),
},
};
};
And get the error:
./lib/api/readProductDataForCategory.ts:1:0
Module not found: Can't resolve 'fs'
1 | import { promises as fs } from "fs";2 | import { join } from "path";
3 |
4 | const readProductDataForCategory = async (dir: string) => {
https://nextjs.org/docs/messages/module-not-found
Import trace for requested module:
./app/schliesszylinder/page.tsx
What is the problem with it?
Answered by Ray
// page.tsx
export default async function Page() {
const productData: any = await readProductDataForCategory(
ProductPath.Schliesszylinder
);
return <Schliesszylinder productData={productData} />
}53 Replies
@Ray cannot use node api with static export
Indian SpitzOP
Thanks. What would be the way to go if I have local .JSON files and would like to read them in for static export?
can you import the json file?
Indian SpitzOP
Sure
yeah try that
Indian SpitzOP
So in Next there is no desired method (getStaticProps, getInitialProps or so) to do that?
Simply importing these in the client side components?
I think you could import the json in the page component and return the props in
getStaticPropsIndian SpitzOP
I think this is going to be difficult. See my code:
import { promises as fs } from "fs";
import { join } from "path";
const readProductDataForCategory = async (dir: string) => {
const configDirectory: string = join(
process.cwd(),
"products",
dir,
"config.json"
);
const entitiesDirectory: string = join(
process.cwd(),
"products",
dir,
"entities"
);
const categoryConfigContent: string = await fs.readFile(
configDirectory,
"utf8"
);
const parsedCategoryConfig = JSON.parse(categoryConfigContent);
const entitiesFileNames: string[] = await fs.readdir(entitiesDirectory);
const dataItems = entitiesFileNames.map(async (entityFileName) => {
const filePath: string = join(entitiesDirectory, entityFileName);
const fileContents: string = await fs.readFile(filePath, "utf8");
const parsedItem = JSON.parse(fileContents);
return parsedItem;
});
return {
config: parsedCategoryConfig,
entities: await Promise.all(dataItems),
};
};
export default readProductDataForCategory;
import { promises as fs } from "fs";
import { join } from "path";
const readProductDataForCategory = async (dir: string) => {
const configDirectory: string = join(
process.cwd(),
"products",
dir,
"config.json"
);
const entitiesDirectory: string = join(
process.cwd(),
"products",
dir,
"entities"
);
const categoryConfigContent: string = await fs.readFile(
configDirectory,
"utf8"
);
const parsedCategoryConfig = JSON.parse(categoryConfigContent);
const entitiesFileNames: string[] = await fs.readdir(entitiesDirectory);
const dataItems = entitiesFileNames.map(async (entityFileName) => {
const filePath: string = join(entitiesDirectory, entityFileName);
const fileContents: string = await fs.readFile(filePath, "utf8");
const parsedItem = JSON.parse(fileContents);
return parsedItem;
});
return {
config: parsedCategoryConfig,
entities: await Promise.all(dataItems),
};
};
export default readProductDataForCategory;
does it work if you change
getInitialProps to getStaticProps?Indian SpitzOP
Nope. "getStaticProps" is not supported in app/. Read more: https://nextjs.org/docs/app/building-your-application/data-fetching
because
getInitialProps will run on server and clientoh you are using app router
Indian SpitzOP
Yes, exactly
then you dont need getInitialProps
// page.tsx
export default async function Page() {
const productData: any = await readProductDataForCategory(
ProductPath.Schliesszylinder
);
return <Schliesszylinder productData={productData} />
}Answer
what is
ProductPath.Schliesszylinder?@Ray what is `ProductPath.Schliesszylinder`?
Indian SpitzOP
'schliesszylinder'
without 'use client' in page component
@Indian Spitz 'schliesszylinder'
is it the part of url?
Indian SpitzOP
Yes, part of the path
then you could create the Page component in
app/product/[category]/page.tsxexport default async function Page({ params }: { params: { category: string }} ) {
const productData: any = await readProductDataForCategory(params.category);
return <Schliesszylinder productData={productData} />
}Indian SpitzOP
The uri shouldn't have a /product/ context route though
app/[category]/page.tsx also possible?
Indian SpitzOP
So a subcontext would make sense
Ok. I have tried that now
It says:
Error: Page "/product/[category]/page" is missing exported function "generateStaticParams()", which is required with "output: export" config.
//[category]/page.tsx
export async function generateStaticParams() {
const productData: any = await readProduct();
return productData.map(p => ({category: p.category})
}something like this
Indian SpitzOP
Oh no. Another problem...
Unhandled Runtime Error
Error: This function is not supported in React Server Components. Please only use this export in a Client Component.
Call Stack
throwNotSupportedError
node_modules\react-redux\dist\rsc.mjs (29:8)
Error: This function is not supported in React Server Components. Please only use this export in a Client Component.
Call Stack
throwNotSupportedError
node_modules\react-redux\dist\rsc.mjs (29:8)
I use the <ReduxProvider>
<ProductPageLayout>
<ProductOverview productData={productData} />
</ProductPageLayout>
</ReduxProvider> here
<ProductPageLayout>
<ProductOverview productData={productData} />
</ProductPageLayout>
</ReduxProvider> here
what function you have in the server component?
Indian SpitzOP
If i use the "use client", then I get:
Code looks like this now:
"use client";
import ProductPageLayout from "@/app/components/PageLayout/ProductPageLayout";
import { ProductOverview } from "@/app/components/Product/ProductOverview/ProductOverview";
import ReduxProvider from "@/app/store/ReduxProvider";
import { ProductPath } from "@/global/consts";
import readProductDataForCategory from "@/lib/api/readProductDataForCategory";
import { enumToArray } from "@/utils/enumToArray";
export default async function Page({
params,
}: {
params: { category: string };
}) {
const productData: any = await readProductDataForCategory(params.category);
return (
<ReduxProvider>
<ProductPageLayout>
<ProductOverview productData={productData} />
</ProductPageLayout>
</ReduxProvider>
);
}
export async function generateStaticParams() {
const allCategorySlugs: any = enumToArray(ProductPath).map((p) => ({
category: p,
}));
return allCategorySlugs;
}
import ProductPageLayout from "@/app/components/PageLayout/ProductPageLayout";
import { ProductOverview } from "@/app/components/Product/ProductOverview/ProductOverview";
import ReduxProvider from "@/app/store/ReduxProvider";
import { ProductPath } from "@/global/consts";
import readProductDataForCategory from "@/lib/api/readProductDataForCategory";
import { enumToArray } from "@/utils/enumToArray";
export default async function Page({
params,
}: {
params: { category: string };
}) {
const productData: any = await readProductDataForCategory(params.category);
return (
<ReduxProvider>
<ProductPageLayout>
<ProductOverview productData={productData} />
</ProductPageLayout>
</ReduxProvider>
);
}
export async function generateStaticParams() {
const allCategorySlugs: any = enumToArray(ProductPath).map((p) => ({
category: p,
}));
return allCategorySlugs;
}
create a
client.tsx inside the folder// [category]/client.tsx
'use client'
export default function Client({ productData }) {
return (
<ReduxProvider>
<ProductPageLayout>
<ProductOverview productData={productData} />
</ProductPageLayout>
</ReduxProvider>
)
}// [category]/page.tsx
import Client from './client'
export default async function Page({
params,
}: {
params: { category: string };
}) {
const productData: any = await readProductDataForCategory(params.category);
return <Client productData={productData} />;
}you could put the Client component in other folder too, it doesn't matter
Indian SpitzOP
Incredible. It works!
Thanks a lot
np
Indian SpitzOP
Do you also have knowledge with i18n?
And custom css?
yeah
Indian SpitzOP
Wrote you a DM