Search code examples
javascriptreactjsmongodbnext.jsvercel

deploy next.js error in vercel ✓ Generation of static pages (5/5) > The export encountered errors in the following paths: /products


I'm trying to deploy a next.js + mongodb project to Vercel, but I can't do it, it keeps giving an error:

Error occurred prerendering page "/products". Read more: https://nextjs.org/docs/messages/prerender-error
SyntaxError: Unexpected token < in JSON at position 0
     at JSON.parse (<anonymous>)
     at parseJSONFromBytes (node:internal/deps/undici/undici:6662:19)
     at successSteps (node:internal/deps/undici/undici:6636:27)
     at node:internal/deps/undici/undici:1236:60
     at node:internal/process/task_queues:140:7
     at AsyncResource.runInAsyncScope (node:async_hooks:203:9)
     at AsyncResource.runMicrotask (node:internal/process/task_queues:137:8)
     at process.processTicksAndRejections (node:internal/process/task_queues:95:5)

    Generating static pages (3/5)

  ✓ Generating static pages (5/5)
> Export encountered errors on following paths:

*products.tsx *

import { GetStaticPaths, GetStaticProps, NextPage } from 'next'
import Head from 'next/head'
import { ReactNode, useState } from 'react'
import { Button, Container, FormFeedback, FormGroup, FormText, Input, Label, Modal, ModalBody, ModalFooter, ModalHeader } from 'reactstrap'
import Header from '../../components/Header'
import ProductsList from '../../components/ProductsList'
import { createProduct, fetchProducts, ProductType } from '../../services/products'
import { Controller, FormProvider, useForm } from 'react-hook-form'
import { maskMoney } from '@/utils/MasksOutputs'
import { convertPriceStringToNumber } from '@/utils/RemoveMasks'
import { useRouter } from 'next/router'
import Image from 'next/image'


export const getStaticProps: GetStaticProps = async ({params}) => {
    const products = await fetchProducts();
    return { props: { products } }
}

const Products: NextPage = (props: {
    children?: ReactNode;
    products?: ProductType[];
}) => {
    const [modal, setModal] = useState(false);
    const router = useRouter();

    const toggle = () => setModal(!modal);

    const methods = useForm({
        defaultValues: {
            name: "",
            price: 0,
            description: "",
            quantity: 0,
            img: ""
        }
    })

    const {control, handleSubmit, watch, reset} = methods;
    const {img} = watch()


    const convertToBase64 = async (file: File) => {
        return new Promise((resolve, reject) => {
            const reader = new FileReader();
            
            reader.onload = function (e) {
                //@ts-ignore
                const base64Content = e.target.result.split(',')[1];
                resolve(base64Content);
            };
        
            reader.onerror = function (error) {
                reject(error);
            };
        

            reader.readAsDataURL(file);
        });
    };

    const onSubmit = async (data: {
        name: string;
        price: number;
        description: string;
        quantity: number;
        img: string;
    }) => {
        const product = await createProduct(data);
        toggle()
        router.push("/products");
        reset({
            name: "",
            price: 0,
            description: "",
            quantity: 0,
            img: ""
        })
    }
    return (
        <>
            <Head>
                <title>Nossos Produtos</title>
                <meta name="description" content="Conheça todos os nossos produtos" />
                <link rel="icon" href="/favicon.ico" />
            </Head>

            <Header />

            <main>
                <Container className="mb-5">
                    <div className="my-5"
                        style={{
                            display: "flex",
                            alignContent: "center",
                            justifyContent: "space-between"
                        }}>
                        <h1>
                            Nossos Produtos
                        </h1>
                        <Button style={{width: "max-content", height: "max-content"}}  color="primary" onClick={toggle}>
                                Criar produto
                        </Button>
                    </div>

                {<ProductsList products={props.products!} />}
    
                    
                    <Modal isOpen={modal} toggle={toggle}>
                        <FormProvider {...methods}>
                            <ModalHeader toggle={toggle}>Criar produto</ModalHeader>
                            <ModalBody>
                                <Controller
                                    name="name"
                                    control={control}
                                    render={({ field: { onChange, value } }) => (
                                        <FormGroup>
                                            <Label for="name">
                                                Nome do produto
                                            </Label>
                                            <Input
                                                id="name"
                                                name="name"
                                                placeholder="ex: pc gamer"
                                                type="text"
                                                value={value}
                                                onChange={onChange}
                                            />
                                        </FormGroup>
                                    )}
                                />

                                <Controller
                                    name="description"
                                    control={control}
                                    render={({ field: { onChange, value } }) => (
                                        <FormGroup>
                                            <Label for="exampleText">
                                                Descrição do produto
                                            </Label>
                                            <Input
                                                id="exampleText"
                                                name="text"
                                                type="textarea"
                                                value={value}
                                                onChange={onChange}
                                            />
                                            <FormFeedback>
                                                Oh noes! that name is already taken
                                            </FormFeedback>
                                        </FormGroup>
                                    )}
                                />
                                <Controller
                                    name="quantity"
                                    control={control}
                                    render={({ field: { onChange, value } }) => (
                                        <FormGroup>
                                            <Label for="exampleText">
                                                Quantos produtos adicionara ao estoque
                                            </Label>
                                            <Input
                                                id="exampleText"
                                                name="text"
                                                type="number"
                                                value={value}
                                                min={1}
                                                max={50}
                                                onChange={onChange}
                                            />
                                        </FormGroup>
                                    )}
                                />
                                <Controller
                                    name="price"
                                    control={control}
                                    render={({ field: { onChange, value } }) => (
                                        <FormGroup>
                                            <Label for="exampleText">
                                                Preço de seu produto
                                            </Label>
                                            <Input
                                                id="exampleText"
                                                name="text"
                                                type="text"
                                                value={maskMoney(value)}
                                                onChange={(e) => onChange(convertPriceStringToNumber(e.target.value))}
                                            />
                                        </FormGroup>
                                    )}
                                />
                                {img && (
                                    <Image
                                        src={img}
                                        alt={"img"}
                                        height={200}
                                        style={{
                                            objectFit: "cover",
                                            display: "block",
                                            margin: "0 auto",
                                            height: "auto"
                                        }}
                                        width={200}
                                        />
                                )}
                                <Controller
                                    name="img"
                                    control={control}
                                    render={({ field: { onChange, value } }) => (
                                        <FormGroup>
                                            <Label for="exampleFile">
                                                Imagem do produto
                                            </Label>
                                            <Input
                                                id="exampleFile"
                                                name="file"
                                                type="file"
                                                onChange={async (e) => {
                                                    //@ts-ignore
                                                    const file = e.target.files[0];
                                                    if (file) {
                                                        const base64Content = await convertToBase64(file);
                                                        onChange(`data:image/jpeg;base64,${base64Content}`);
                                                    }
                                                }}
                                            />
                                            
                                        </FormGroup>
                                    )}
                                />
                                
                        </ModalBody>
                        <ModalFooter>
                            <Button color="primary" onClick={handleSubmit(onSubmit)}>
                                Adicionar produto
                            </Button>{' '}
                        
                        </ModalFooter>
                    </FormProvider>
                    </Modal>
                </Container>
            </main>
        </>
    )
}

export default Products;

fetchfunction

export const fetchProducts = async () => {
    try {
        const products: ProductType[] = await fetch(`${process.env.NEXT_PUBLIC_APIURL}/api/products`).then(res => res.json())
        console.log('Products:');
        return products;
    } catch (error) {
        console.error('Error fetching products:', error);
        throw error;
    }
}

observation: in vercel the environment variable is already set

running locally everything is working, both the pages and the apis I tried to make the request within get static props but it didn't work either I'm using pages do next


Solution

  • Is this your first time deploying a server?

    If so, your server may not have an API route because it is not yet deployed.

    For the first deployment, do not use the API route, but instead deploy it with an empty value. Once your server is up and running, change your code to use the API route and redeploy.