wise-white
wise-white16mo ago

[Nextjs | MUI | Supabase] Slow initial load on Vercel

I'm using Nextjs, MaterialUI, and Supabase. I deployed the app to Vercel under the hobby plan and kept getting a 504 timeout error on a Free / Hobby account. Here's the link: https://meal-mind.vercel.app/ I started a pro trial with Vercel since I know they cap the load time, and now my app works. Here's the link: https://www.mealmind.app/ But there's still an extremely slow loading time to start (sometimes it loads fast though). Locally it shows a webpack-hmr taking 6+ minutes. But on Vercel it's just the app page that loads slow. I've tried everything to try to fix this, even worked with my mentor who's better at backend stuff than I am (I'm still pretty new to this entire tech stack) and we couldn't figure it out. I also tried to deploy it on Netlify, and same issue. Is there somewhere I should look or test in? Any suggestions?
9 Replies
refine-support-bot
Hi, I am refine support bot :wave:. I am here to help you with your question. I searched for the answer to your question in the refine documentation and found an answer! 🏆
Answer: It is difficult to provide a definitive answer without further information. It is possible that the slow initial load time is due to the configuration of the Vercel or Netlify accounts, or the code itself. It is recommended to review the code and the configuration of the accounts to identify the source of the issue. SOURCES: N/A

Note: If this is the answer you need, then we are very lucky. If not, please wait for someone from the refine core team or the community to try to help you.
wise-white
wise-white16mo ago
Environment variables between Vercel and Supabase are correct. The configuration seems to be correct in Vercel... The only difference was that I moved the project to a paid account so that the 10+ second load time would not get capped / timed out by Vercel. But there must be a way to shorten the load time.
extended-salmon
extended-salmon16mo ago
Hey @kitkatnik, checking the issue now. How many resources do you have? Do you have getServerSideProps inside your routes? If so, are they taking too long to resolve?
wise-white
wise-white16mo ago
Here's the Refine component. All resources are being used except for profiles which will be used in a later date.
No description
wise-white
wise-white16mo ago
Here's the [[...refine]].tsx file with getServerSideProps. Ignore my comments, I was just trying to understand what it does and writing it down so that I remember later lol
No description
wise-white
wise-white16mo ago
How do I check if they're taking too long to resolve? This is what happens when I go to the website for the first time: https://www.loom.com/share/477d6ee04f47480196360b691b09d079 After the first time, it loads super quick every time. But I had to upgrade Vercel to be able to do that. Since I can't get past the timeout on my free Hobby plan, it never loads there.
wise-white
wise-white16mo ago
@kitkatnik Can you use console.time feature between method calls? Let's see which call takes how much time, so we can debug it.
wise-white
wise-white16mo ago
@batuhanw Here are the results from my browser console (firefox) and vscode console
No description
No description
wise-white
wise-white15mo ago
Here's the [[...refine]].tsx code so you can see my console.time logs
import { GetServerSideProps } from "next";
import {
NextRouteComponent,
handleRefineParams,
checkAuthentication,
} from "@pankod/refine-nextjs-router";
import { dataProvider } from "@pankod/refine-supabase";

import { authProvider } from "src/authProvider";
import { supabaseClient } from "src/utility";

// import statements here

export const getServerSideProps: GetServerSideProps<{
initialData?: unknown;
}> = async (context) => {
console.time("getServerSideProps");

// req, res

console.time("handleRefineParams");
const { resource, action, id } = handleRefineParams(context.params?.refine);
console.timeEnd("handleRefineParams");

console.time("checkAuthentication");
const { isAuthenticated, ...props } = await checkAuthentication(
authProvider,
context
);
console.timeEnd("checkAuthentication");

if (!isAuthenticated && resource !== "registration-success") {
console.timeEnd("getServerSideProps");
return props;
}

try {
if(resource === "registration-success"){
console.timeEnd("getServerSideProps");
return {props: {}};

} else if (resource && action === "show" && id) {
console.time("dataProvider getOne");
const data = await dataProvider(supabaseClient).getOne({
resource: resource.slice(resource.lastIndexOf("/") + 1),
id,
});
console.timeEnd("dataProvider getOne");
return {
props: {
// initialData: data,
},
};
} else if (resource && !action && !id) {
console.time("dataProvider getList");
const data = await dataProvider(supabaseClient).getList({
resource: resource.slice(resource.lastIndexOf("/") + 1),
});
console.timeEnd("dataProvider getList");
return {
props: {
initialData: data,
},
};
}
} catch (error) {
console.timeEnd("getServerSideProps");
return { props: {} };
}

console.timeEnd("getServerSideProps");
return {
props: {},
};
};

export default NextRouteComponent;

import { GetServerSideProps } from "next";
import {
NextRouteComponent,
handleRefineParams,
checkAuthentication,
} from "@pankod/refine-nextjs-router";
import { dataProvider } from "@pankod/refine-supabase";

import { authProvider } from "src/authProvider";
import { supabaseClient } from "src/utility";

// import statements here

export const getServerSideProps: GetServerSideProps<{
initialData?: unknown;
}> = async (context) => {
console.time("getServerSideProps");

// req, res

console.time("handleRefineParams");
const { resource, action, id } = handleRefineParams(context.params?.refine);
console.timeEnd("handleRefineParams");

console.time("checkAuthentication");
const { isAuthenticated, ...props } = await checkAuthentication(
authProvider,
context
);
console.timeEnd("checkAuthentication");

if (!isAuthenticated && resource !== "registration-success") {
console.timeEnd("getServerSideProps");
return props;
}

try {
if(resource === "registration-success"){
console.timeEnd("getServerSideProps");
return {props: {}};

} else if (resource && action === "show" && id) {
console.time("dataProvider getOne");
const data = await dataProvider(supabaseClient).getOne({
resource: resource.slice(resource.lastIndexOf("/") + 1),
id,
});
console.timeEnd("dataProvider getOne");
return {
props: {
// initialData: data,
},
};
} else if (resource && !action && !id) {
console.time("dataProvider getList");
const data = await dataProvider(supabaseClient).getList({
resource: resource.slice(resource.lastIndexOf("/") + 1),
});
console.timeEnd("dataProvider getList");
return {
props: {
initialData: data,
},
};
}
} catch (error) {
console.timeEnd("getServerSideProps");
return { props: {} };
}

console.timeEnd("getServerSideProps");
return {
props: {},
};
};

export default NextRouteComponent;

And here's the authProvider.ts
import { AuthProvider } from "@pankod/refine-core";

import nookies from "nookies";

import { supabaseClient } from "./utility";

export const authProvider: AuthProvider = {
login: async ({ email, password }) => {
console.time("authProvider login")
const { data, error } = await supabaseClient.auth.signInWithPassword({
email,
password,
});

if (error) {
console.timeEnd("authProvider login")
return Promise.reject(error);
}

if (data?.session) {
nookies.set(null, "token", data.session.access_token, {
maxAge: 30 * 24 * 60 * 60,
path: "/",
});
console.timeEnd("authProvider login")
return Promise.resolve();
}

// for third-party login
return Promise.resolve(false);
},
logout: async () => {
console.time("authProvider logout")
nookies.destroy(null, "token");
const { error } = await supabaseClient.auth.signOut();

if (error) {
console.timeEnd("authProvider logout")
return Promise.reject(error);
}

console.timeEnd("authProvider logout")
return Promise.resolve("/");
},
checkError: () => Promise.resolve(),
checkAuth: async (ctx) => {
console.time("authProvider checkAuth")
const { token } = nookies.get(ctx);
const { data } = await supabaseClient.auth.getUser(token);
const { user } = data;

if (user) {
console.timeEnd("authProvider checkAuth")
return Promise.resolve();
}
console.timeEnd("authProvider checkAuth")
return Promise.reject();
},
getPermissions: async () => {
console.time("authProvider getPermissions")
const user = await supabaseClient.auth.getUser();

if (user) {
console.timeEnd("authProvider getPermissions")
return Promise.resolve(user.data.user?.role);
}
},
getUserIdentity: async () => {
console.time("authProvider getUserIdentity")
const { data: { user } } = await supabaseClient.auth.getUser();

if (user) {
console.timeEnd("authProvider getUserIdentity")
return Promise.resolve({
...user,
name: user.email,
});
}
console.timeEnd("authProvider getUserIdentity")
return Promise.reject()
},
register: async ({ email, password }) => {
console.time("authProvider register")
const { data, error } = await supabaseClient.auth.signUp({
email,
password
});

if (error) {
console.timeEnd("authProvider register")
return Promise.reject(error);
}

if (data) {
console.timeEnd("authProvider register")
return Promise.resolve("/registration-success");
}
},
forgotPassword: async ({ email }) => {
console.time("authProvider forgotPassword")
const { data, error } = await supabaseClient.auth.resetPasswordForEmail(
email,
{
redirectTo: `${window.location.origin}/update-password`,
}
);

if (error) {
console.timeEnd("authProvider forgotPassword")
return Promise.reject(error);
}

if (data) {
console.timeEnd("authProvider forgotPassword")
return Promise.resolve();
}
},
updatePassword: async ({ password }) => {
console.time("authProvider updatePassword")
const { data, error } = await supabaseClient.auth.updateUser({
password,
});
}
}
import { AuthProvider } from "@pankod/refine-core";

import nookies from "nookies";

import { supabaseClient } from "./utility";

export const authProvider: AuthProvider = {
login: async ({ email, password }) => {
console.time("authProvider login")
const { data, error } = await supabaseClient.auth.signInWithPassword({
email,
password,
});

if (error) {
console.timeEnd("authProvider login")
return Promise.reject(error);
}

if (data?.session) {
nookies.set(null, "token", data.session.access_token, {
maxAge: 30 * 24 * 60 * 60,
path: "/",
});
console.timeEnd("authProvider login")
return Promise.resolve();
}

// for third-party login
return Promise.resolve(false);
},
logout: async () => {
console.time("authProvider logout")
nookies.destroy(null, "token");
const { error } = await supabaseClient.auth.signOut();

if (error) {
console.timeEnd("authProvider logout")
return Promise.reject(error);
}

console.timeEnd("authProvider logout")
return Promise.resolve("/");
},
checkError: () => Promise.resolve(),
checkAuth: async (ctx) => {
console.time("authProvider checkAuth")
const { token } = nookies.get(ctx);
const { data } = await supabaseClient.auth.getUser(token);
const { user } = data;

if (user) {
console.timeEnd("authProvider checkAuth")
return Promise.resolve();
}
console.timeEnd("authProvider checkAuth")
return Promise.reject();
},
getPermissions: async () => {
console.time("authProvider getPermissions")
const user = await supabaseClient.auth.getUser();

if (user) {
console.timeEnd("authProvider getPermissions")
return Promise.resolve(user.data.user?.role);
}
},
getUserIdentity: async () => {
console.time("authProvider getUserIdentity")
const { data: { user } } = await supabaseClient.auth.getUser();

if (user) {
console.timeEnd("authProvider getUserIdentity")
return Promise.resolve({
...user,
name: user.email,
});
}
console.timeEnd("authProvider getUserIdentity")
return Promise.reject()
},
register: async ({ email, password }) => {
console.time("authProvider register")
const { data, error } = await supabaseClient.auth.signUp({
email,
password
});

if (error) {
console.timeEnd("authProvider register")
return Promise.reject(error);
}

if (data) {
console.timeEnd("authProvider register")
return Promise.resolve("/registration-success");
}
},
forgotPassword: async ({ email }) => {
console.time("authProvider forgotPassword")
const { data, error } = await supabaseClient.auth.resetPasswordForEmail(
email,
{
redirectTo: `${window.location.origin}/update-password`,
}
);

if (error) {
console.timeEnd("authProvider forgotPassword")
return Promise.reject(error);
}

if (data) {
console.timeEnd("authProvider forgotPassword")
return Promise.resolve();
}
},
updatePassword: async ({ password }) => {
console.time("authProvider updatePassword")
const { data, error } = await supabaseClient.auth.updateUser({
password,
});
}
}
So I made a very simple Refine app with CRA and then made the same app with Nextjs (both using Supabase) and I have the same slow load time issues with Nextjs, but not with CRA. Could it be an issue of using Nextjs with Supabase?