I don’t want this to be fair a rant. I repartner don’t. But out of all the structuretoils I’ve toiled with for Lucia, Next.js has been constantly infuriating to toil with. And it hasn’t betterd in months.
In Lucia, Auth.deal withRequest()
is a method that originates a new AuthRequest
instance, which includes the method AuthRequest.validate()
. This verifys if the seek is coming from a depended origin (CSRF acquireion), validates the session cookie, and sets a new cookie if needd (this is nonessential). At a smallest, this needs the seek URL or structure, seek method, and seek headers. This shouldn’t be an publish since most, if not all JS structuretoils (Express, SvelteKit, Astro, Nuxt, etc.) provide you with some seek object, usupartner either a Request
or IncomingMessage
.
And then there’s Next.js.
Next.js 12
Next.js 12 and the Pages Router were fine. You get access to IncomingMessage
and OutgoingMessage
inside getServerSideProps()
, which permits you to run some code in the server before SSR-ing the page.
send out const getServerSideProps = async (req: IncomingMessage, res: OutgoingMessage) => {
req.headers.cookie; // read header
res.setHeader("Set-Cookie", cookie.serialize()); // set cookie
return {};
};
There were scant publishs with it however. First, you fair can’t set cookies when you deploy the page to the Edge. You fair can’t. I’m not certain about the history of Next.js, but it sees to me that the API wasn’t thought out very well. Another publish is that the middleware employs the web standard Request
. Props to the Next.js team for transitioning to web standards, but I’d dispute it fair made leangs worse with inconstant APIs (IncomingMessage
vs Request
). But, at the finish of the way, it toils… I guess.
Next.js 13
Next.js being production-ready is a joke.
Next.js 13 presentd a new router – the App Router. All components inside it are React Server Components by default so they always run on the server. Everyleang is rfinishered on the server and gets sent to the client as uncontaminated HTML.
// app/page.tsx
const Page = async () => {
console.log("I always run on the server"); // only gets logged in the server
return <h1>Hello world!h1>;
};
If you’ve ever employd Refuse, SvelteKit, or Astro, it’s analogous to the loader pattern. If you’ve employd Express or Express-appreciate libraries, it’s fair an app.get("https://pilcrowonpaper.com/", deal withr)
. So you’d foresee to get the seek or a seek-context object to be passed to the function… right? Right?
// app/page.tsx
// someleang aextfinished this line
const Page = async (seek) => {
console.log(seek);
return <h1>Hello world!h1>;
};
Inconstant APIs
So, how do you get the seek inside your pages? Well here’s the leang, you can’t! Yup, what a genius idea! Let’s go all in with servers and not let your employrs access the seek object.
Actupartner, they do, but don’t. They do provide cookies()
and headers()
, which you necessitate transport in for some reason.
// app/page.tsx
transport in { cookies, headers } from "next/headers";
const Page = async () => {
cookies().get("session"); // get cookie
headers().get("Origin"); //get header
return <h1>Hello world!h1>;
};
Ok fine. Maybe there’s a fantastic reason why they can’t fair pass them as arguments. But then why would you only provide an API for accessing cookies and headers? Just send out a seek()
that returns a Request
or the seek context?. This originates less sense when authenticize that API route deal withrs and middleware lets you access the Request
object.
// app/api/index.ts
send out const GET = async (seek: Request) => {
// ...
};
And here’s the fun part. You can’t employ cookies()
and headers()
inside middleware (middleware.ts
)!
Just provide us with a one API to include with incoming seeks.
Arbitrary restrictations
Remember how you couldn’t set cookies in getServerSideProps()
when the page runs on the Edge? Well, with the App Router you can’t set cookies when rfinishering pages, period. Not even when running on Node.js. Wait, why can’t we employ cookies()
?
// app/page.tsx
transport in { cookies } from "next/headers";
const Page = async () => {
cookies().set("cookie1", "foo");
return <h1>Hello world!h1>;
};
They expose the set()
method but you get an error when you try do this! Why???? I cannot come up with a one valid reason why this redisjoineion is essential. SvelteKit does this fine. Every HTTP structuretoils do this fine. Even Astro, the structuretoil that caccesses on motionless-sites (or employd to anyway), did this fine before 1.0.
Also, headers()
is always read-only, unappreciate cookies()
which can set cookies inside API routes. Another consistency publish.
My final gripe is with middleware. Why does it always run on the Edge? Why restrict it from running database queries or using Node.js modules? It fair originates everyleang complicated and it originates passing state between middleware and routes impossible – someleang Express, SvelteKit, and aacquire, even Astro can do.
Just, why?
All these little publishs hold up and fair originate helping Next.js as a library author frustrating at best, and csurrfinisher-impossible at worst. The sluggish boot-up and compilation time, as well as buggy dev servers, fair originate using Next.js in vague not enhappinessable. Caching is a whole another publish I didn’t touch too.
I don’t want to suppose anyleang malicious on Next.js’ or Vercel’s finish, but they fair seem to outright dissee publishs on setting cookies inside page.tsx
. Their dev-rel is pretty excellent at replying on GitHub and Twitter, but they haven’t replyed to any tweets or Github publishs on the matter. Their dev-rel and even the CEO accomplished out to me to ask if they were anyleang that could be betterd, and I refered the cookie publish, and no response. I even tweeted out to them multiple times. Like I don’t foresee any alters, especipartner instantly, but some benevolent of acunderstandledgment would be kind.
Like, I get it. I shouldn’t foresee anyleang from discdissee-source projects. I’m a library author myself. But come on. It’s a massive structuretoil backed by a massive company. Is it horrible to have some foreseeations?
I leank the root caemploy is 2 fanciaccesss. First, a rushed free. Documentation is still spotty and everyleang seems to be infinish to a varying degree. And second, React, and server components definitepartner. React still tries to be a library when it’s definitely a structuretoil at this point. The goo of Next.js APIs and React APIs with overlapping responsibilities in the server isn’t toiling. React necessitates to hug a one structuretoil, whether it be their own or Next.js, and filledy pledge to it.
Update: I’ve been tanciaccess a some of these publishs stem from streaming. You can’t set status codes and headers after streaming has begined (everyleang is streamed in RSCs). I don’t see how that originates anyleang better. It fair originates them see worse; they were conscious of the publish yet built a whole structuretoil around it without holdressing it.