Next.js Discord

Discord Forum

Trouble with deploying

Answered
Argente Brun posted this in #help-forum
Open in Discord
Avatar
Argente BrunOP
Hi everyone! Im new at next. I'm trying to deploy project with route handlers on vercel.
import ProductsPageScene from "@/scenes/ProductsPageScene";
import { env } from "process";

const getProducts = async () => {
    try {
        if (env.PRODUCTION_LINK) {
            const res = await fetch(env.PRODUCTION_LINK + `/api/products`);
            const { data } = await res.json();
            return data;
        }
    } catch (err) {
        throw new Error(`ERROR: ${err}`);
    }
};

const ProductsPage = async () => {
    const products = await getProducts();

    return <ProductsPageScene products={products} />;
};

export default ProductsPage;

PRODUCTION_LINK="https://impilo.vercel.app"
API_LINK="http://impilomedicalsystems.co.za"

import { NextResponse } from "next/server";

import { env } from "process";

export async function GET() {
    const res = await fetch(`${env.API_LINK}/wp-json/xlsx/v1/computer`);
    const data = await res.json();

    return NextResponse.json({ data });
}


Im getting 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)
- info Generating static pages (10/10)

> Export encountered errors on following paths:
        /products/page: /products


Help me to fix this please
Answered by risky
well the original thing is that you have to:
* look at code for api/products
* move it out to a "utils" or smth file
* import that function to the api route and use normally
* import into server component and use
View full answer

93 Replies

Avatar
Argente BrunOP
I tryed to remove production_link. It didn't help at all
Avatar
instead of res.json, can you do res.text and console.log the value (ti may show the error better)
Avatar
Argente BrunOP
I'm getting TS error. Because data provides array of objects
Avatar
i just meant as a tempory thing, just to show the error, not actualy to mess with the code
like just return after you get the value,
as your error looks like it would be HTML, but we can't see the full error here (from your api)
Avatar
Argente BrunOP
import ProductsPageScene from "@/scenes/ProductsPageScene";
import { env } from "process";

const getProducts = async () => {
    try {
        if (env.PRODUCTION_LINK) {
            const res = await fetch(env.PRODUCTION_LINK + `/api/products`);
            console.log(await res.text());
            // const { data } = await res.json();
            // return data;
        }
    } catch (err) {
        throw new Error(`ERROR: ${err}`);
    }
};

const ProductsPage = async () => {
    const products = await getProducts();

    // return <ProductsPageScene products={products} />;
    return "";
};

export default ProductsPage;
Avatar
ye just try that
Avatar
Argente BrunOP
<!DOCTYPE html><html><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><title>404: This page could not be found</title><meta name="next-head-count" content="3"/><noscript data-n-css=""></noscript><script defer="" nomodule="" src="/_next/static/chunks/polyfills-78c92fac7aa8fdd8.js"></script><script src="/_next/static/chunks/webpack-4ea4d72d9fb1d23a.js" defer=""></script><script 
 defer=""></script><script src="/_next/static/chunks/main-6407795f441898e6.js" defer=""></script><script src="/_next/static/chunks/pages/_app-52924524f99094ab.js" defer=""></script><script src="/_next/static/chunks/pages/_error-c92d5c4bb2b49926.js" defer=""></script><script src="/_next/static/-_4cDkHYQTvEogjyKcRKK/_buildManifest.js" defer=""></script><script src="/_next/static/-_4cDkHYQTvEogjyKcRKK/_ssgManifest.js" defer=""></script></head><body><div id="__next"><div style="font-family:system-ui,&quot;Segoe UI&quot;,Roboto,Helvetica,Arial,sans-serif,&quot;Apple Color Emoji&quot;,&quot;Segoe UI Emoji&quot;;height:100vh;text-align:center;display:flex;flex-direction:column;align-items:center;justify-content:center"><div style="line-height:48px"><style>body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}</style><h1 class="next-error-h1" style="display:inline-block;margin:0 20px 0 0;padding-right:23px;font-size:24px;font-weight:500;vertical-align:top">404</h1><div style="display:inline-block"><h2 style="font-size:14px;font-weight:400;line-height:28px">This page could not be found<!-- -->.</h2></div></div></div></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{"statusCode":404}},"page":"/_error","query":{},"buildId":"-_4cDkHYQTvEogjyKcRKK","nextExport":true,"isFallback":false,"gip":true,"scriptLoader":[]}</script></body></html>
Avatar
hmm a 404 page
Avatar
Argente BrunOP
I'm getting this because production_link is wrong on localhost
Avatar
ahhh, you should fix it then
Avatar
Argente BrunOP
import ProductsPageScene from "@/scenes/ProductsPageScene";
import { env } from "process";

const getProducts = async () => {
    try {
        if (env.PRODUCTION_LINK) {
            const res = await fetch(env.LOCALHOST + `/api/products`);
            console.log(await res.text());
            // const { data } = await res.json();
            // return data;
        }
    } catch (err) {
        throw new Error(`ERROR: ${err}`);
    }
};

const ProductsPage = async () => {
    const products = await getProducts();

    // return <ProductsPageScene products={products} />;
    return "";
};

export default ProductsPage;
{"data":[{"ID":6339,"post_author":"1","post_date":"2023-09-25 16:33:50","post_date_gmt":"2023-09-25 14:33:50","post_content":"","post_title":"Chison SonoAir 30","post_excerpt":"","post_status":"publish","comment_status":"closed","ping_status":"closed","post_password":"","post_name":"chison-sonoair-30","to_ping":"","pinged":"","post_modified":"2023-09-25 16:33:50","post_modified_gmt":"2023-09-25 14:33:50","post_content_filtered":"","post_parent":0,"guid":"https://impilomedicalsystems.co.za/computer/6339/","menu_order":0,"post_type":"computer","post_mime_type":"","comment_count":"0","filter":"raw","meta_code":"SA30","meta_price":"88088","meta_description":"Portable colour doppler unit with Convex  and Linear Probes","meta_unitType":"portable","meta_images":["https://impilomedicalsystems.co.za/wp-content/uploads/2023/10/E1-3.png"],"meta_accessorys":[{"ID":6269,"post_author":"1","post_date":"2023-09-16 16:38:55","post_date_gmt":"2023-09-16 14:38:55","post_content":"","post_title":"Black and white thermal ultrasound printer","post_excerpt":"","post_status":"publish","comment_status":"closed","ping_status":"closed","post_password":"","
Avatar
so is the api the same server as nextjs?
Avatar
Argente BrunOP
it's quite big
Avatar
yeah that looks good, so now go back to your other code
Avatar
Argente BrunOP
import ProductsPageScene from "@/scenes/ProductsPageScene";
import { env } from "process";

const getProducts = async () => {
    try {
        if (env.PRODUCTION_LINK) {
            const res = await fetch(env.LOCALHOST + `/api/products`);
            // console.log(await res.text());
            const { data } = await res.json();
            return data;
        }
    } catch (err) {
        throw new Error(`ERROR: ${err}`);
    }
};

const ProductsPage = async () => {
    const products = await getProducts();

    // return <ProductsPageScene products={products} />;
    return "";
};

export default ProductsPage;

like this?
Avatar
like if the api is running on the same server and requesting server component, you should just follow: https://nextjs-faq.com/fetch-api-in-rsc
Avatar
Argente BrunOP
Now its wrong link
http://localhost:3000/undefined/api/products

BUT in console im getting correct data
Avatar
intresting...
Avatar
Argente BrunOP
Why??? It's too hard
Image
But I'm getting data
Avatar
o.O so it doesn't work?
Avatar
Argente BrunOP
It's working on my machine, but on vercel don't
deploy error
Error: ERROR: TypeError: Failed to parse URL from /api/products
    at getProducts (/vercel/path0/.next/server/app/products/page.js:541:15)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async ProductsPage (/vercel/path0/.next/server/app/products/page.js:545:22)
Error occurred prerendering page "/products". Read more: https://nextjs.org/docs/messages/prerender-error
Error: ERROR: TypeError: Failed to parse URL from /api/products
    at getProducts (/vercel/path0/.next/server/app/products/page.js:541:15)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async ProductsPage (/vercel/path0/.next/server/app/products/page.js:545:22)
Avatar
so are you sending using relative url for fetch on server side? (ie not https://)
Avatar
Argente BrunOP
You mean In route.ts?
Or in Page
Avatar
like how are you using the route
Avatar
Argente BrunOP
in documentation was example
You create route.ts, describe GET or somethink Method
then
In page I'm trying to get this GET method from server api
fetch("http://localhost:3000/api/products")
It's working localy
But it doesn't on vercel
Avatar
but is fetch("http://localhost:3000/api/products") done in a client or server component?
Avatar
Argente BrunOP
My boss tells me, that i've to remove localhost. That it is useless, so i left only fetch("/api/products")
But same error
server
Avatar
basicly don't need to make a route for it and just do the code
Avatar
Argente BrunOP
Can i fix this without any external libs?
Avatar
yes
just do the code that /api/products has, but without fetching
Avatar
Argente BrunOP
without fetching?? I don't understand how
import ProductsPageScene from "@/scenes/ProductsPageScene";
import { env } from "process";

// const getProducts = async () => {
//     try {
//         if (env.PRODUCTION_LINK) {
//             const res = await fetch(env.LOCALHOST + `/api/products`);
//             // console.log(await res.text());
//             const { data } = await res.json();
//             return data;
//         }
//     } catch (err) {
//         throw new Error(`ERROR: ${err}`);
//     }
// };

const ProductsPage = async () => {
    const res = await fetch(`/api/products`);
    const { data } = await res.json();

    return <ProductsPageScene products={data} />;
    return "";
};

export default ProductsPage;

I tried to do this
Avatar
so, what is your code of /api/products... whatever it is, copy it out into another file which the api route imports and uses
then on your server compoent, also import and use
no need for fetching own api
Avatar
Argente BrunOP
import ProductsPageScene from "@/scenes/ProductsPageScene";
import { env } from "process";

// const getProducts = async () => {
//     try {
//         if (env.PRODUCTION_LINK) {
//             const res = await fetch(env.LOCALHOST + `/api/products`);
//             // console.log(await res.text());
//             const { data } = await res.json();
//             return data;
//         }
//     } catch (err) {
//         throw new Error(`ERROR: ${err}`);
//     }
// };

const ProductsPage = async () => {
    const res = await fetch(`${env.API_LINK}/wp-json/xlsx/v1/computer`);
    const data = await res.json();

    console.log(data);

    return <ProductsPageScene products={data} />;
    return "";
};

export default ProductsPage;

Like this?
Avatar
so is wp-json/xlsx/v1/computer an external api or your own from the next server?
Avatar
Argente BrunOP
external
Avatar
then thats good to keep
Avatar
Argente BrunOP
So can you explain me what the reason of route handlers?
Avatar
its your other one thats on the same nextjs server thats the issue
it just allows you to make a pathname and return any http response
whereas normal pages have to be react
so route handlers can be used for apis (but only for use of client)
Avatar
Argente BrunOP
ohh wait
Route (app)                                Size     First Load JS
┌ ○ /                                      2.23 kB         116 kB
├ ○ /api/products                          0 B                0 B
├ λ /api/products/[id]                     0 B                0 B
├ ○ /favicon.ico                           0 B                0 B
├ λ /pricing/[id]                          2.75 kB         133 kB
├ ○ /products                              1.01 kB         132 kB
├ λ /products/[id]                         24.1 kB         155 kB
├ ○ /quotes                                4.46 kB         106 kB
├ ○ /roi-calculator                        145 B          78.6 kB
├ ○ /training                              145 B          78.6 kB
â”” â—‹ /training/in-person                    145 B          78.6 kB
+ First Load JS shared by all              78.4 kB
  ├ chunks/596-2b60cd87bb49976c.js         25.9 kB
  ├ chunks/fd9d1056-158bd2a597018d29.js    50.5 kB
  ├ chunks/main-app-14edfdbb6ecc4631.js    215 B
  â”” chunks/webpack-f1b9d75276075947.js     1.82 kB

Route (pages)                              Size     First Load JS
─ ○ /404                                   182 B          75.8 kB
+ First Load JS shared by all              75.6 kB
  ├ chunks/framework-8883d1e9be70c3da.js   45 kB
  ├ chunks/main-8006ccefe3bcf712.js        28.6 kB
  ├ chunks/pages/_app-52924524f99094ab.js  195 B
  â”” chunks/webpack-f1b9d75276075947.js     1.82 kB

λ  (Server)  server-side renders at runtime (uses getInitialProps or getServerSideProps)
â—‹  (Static)  automatically rendered as static HTML (uses no initial props)
There are server and client pages
and now /products is static
like /api/products
Avatar
is it meant to be static? if not you can do export const revalidate = 0
Avatar
Argente BrunOP
This is catalog of products, so i guess yeeees
may be
Avatar
well the original thing is that you have to:
* look at code for api/products
* move it out to a "utils" or smth file
* import that function to the api route and use normally
* import into server component and use
Answer
Avatar
and read the link i have sent: https://nextjs-faq.com/fetch-api-in-rsc
Avatar
Argente BrunOP
Am i understood you right?
I moved out code in /api/products route.ts into utils/route.ts
import { NextResponse } from "next/server";

import { env } from "process";

export async function GET() {
    const res = await fetch(`${env.API_LINK}/wp-json/xlsx/v1/computer`);
    const data = await res.json();

    return NextResponse.json({ data });
}

And export this in page

import ProductsPageScene from "@/scenes/ProductsPageScene";
import { GET } from "@/utils/route";

const ProductsPage = async () => {
    const res = await GET();
    const { data } = await res.json();

    return <ProductsPageScene products={data} />;
};

export default ProductsPage;
Avatar
no...
you make your utils/route.ts file do the fetch and just return the fetched value
then in product, you would use it (no .json needed)
and then you can still have your /api/products file, just import utils/route.ts and use NextResponse on that after awaited
Avatar
Argente BrunOP
i think i don't understand
You mean this?
import { NextResponse } from "next/server";

import { env } from "process";

export async function GET() {
    const res = await fetch(`${env.API_LINK}/wp-json/xlsx/v1/computer`);
    const data = await res.json();

    return data;
}


import ProductsPageScene from "@/scenes/ProductsPageScene";
import { GET } from "@/utils/route";

const ProductsPage = async () => {
    const data = await GET();

    return <ProductsPageScene products={data} />;
};

export default ProductsPage;
Avatar
yeah 🎉
and you can chosse a better name then get and file name
Avatar
Argente BrunOP
So now i've useless route in api
Is this ok?
Avatar
you can keep or remove it...
Avatar
Argente BrunOP
Image
Avatar
once you test it, we will see
sorry for sounding confusing ;(
Avatar
Argente BrunOP
don't sorry please... You did a great job!
Avatar
Argente BrunOP
MAAAN. Im so confused. There was error in api
http instead of https
that's 404 code
Avatar
o.O
Avatar
Argente BrunOP
Thank you so much for your time and patience
It'll be great have more like you, Thank You!
Avatar
no problem... i like helping :), also if your question is solved, can you use the mark solution option 🙂 (or tell me which message to do)
Avatar
Argente BrunOP
No problem. How can i do this? I don't see it
that message i think
Avatar
its mentioned in the first message by the bot, but as i have "helper role", i can do it manualy 🙂
Avatar
Argente BrunOP
Okay. Take care of yourself
Avatar
you too, if you have any more questions, fell free to make a new post 🙂