Issue 004: Build your own Next.js

Written by Rico Sta. Cruz
(@rstacruz) · 4 Jan 2023

Do you need Next.js just to get SSR working? Maybe there’s another way.

In this article:
  1. Build your own Next.js framework
  2. Make things slower to make things feel fast
  3. GraphQL? Rest? How about neither
  4. Build-your-own linters
  5. Compiling TypeScript to Lua

Build your own Next.js framework

There’s a lot of frameworks for server-side rendering (SSR), and they’re all highly-opinionated. Sometimes these opinion can clash with what you want. Instead… what if we don’t use a framework?

vite-plugin-ssr is an alternative. It requires a bit more DIY’ing, but it unlocks flexibility that others don’t quite have:

  • Use any frontend framework (React, Vue, Svelte, Solid, etc)
  • Use as middleware in anything (Express, Fastify, Koa, etc)
  • Deploy anywhere, even Cloudflare Workers with its modest 1MB size limit
  • Gets you Next-like file system routing and SSR features

It’s not a framework. It’s a library that lets you build your own framework. I think this makes for a great playground for experimenting with new tech!

Make things slower to make things feel fast

  • Functions taking a long time in the browser? Try pausing execution with await and setTimeout.
  • It will take longer to run, but it will make the UI feel faster.

I just came across a unique performance optimisation that’s just so obvious: what if we make functions pause every now and then to breathe?

Using async/await makes this very easy. A calling simple function to use setTimeout(0) will allow other things to run in the background. It’s really counter-intuitive, but pausing work periodically can things feel faster by making UI feel more responsive.

async myLongRunningFunction() {
for (let i = 0; i < list.length; i++) {
// Every 5 items, let other things run
if (i % 5 === 0) await yieldToMain();
function yieldToMain() {
return new Promise((resolve) => setTimeout(resolve, 0));
See: Optimizing long tasks (
Hey! I write articles about web development and productivity. If you'd like to support me, subscribe to the email list so you don't miss out on updates.

GraphQL? Rest? How about neither

  • Wildcard allows building API’s with functions, kind of like RPC.
  • It’s less verbose than GraphQL, more expressive than REST.

When building an API, it seems the only choices are GraphQL and Rest. But before there was Rest, it was popular to expose raw, arbitrary functions called remote procedure calls (RPC’s.)

RPC’s don’t require you to to build your data model as objects and resources like GraphQL and Rest do, which might make it a good fit for simpler API’s.

Build-your-own linters

  • Sylver is a way to write tools for code.
  • Today, it supports JavaScript, Go, and JSON.
  • Use it to write your own custom lint rules.

I recall seeing places like Facebook have custom linters for their code which can validate business logic—for example, enforcing the use of design tokens for building UI’s.

Building linters can probably be done by hacking around a JavaScript parser like Esprima, but it looks like there’s an interesting alternative now. Sylver looks promising for this use case!

Compiling TypeScript to Lua

  • Write Lua scripts using TypeScript.
  • Lua is used in Neovim, Hammerspoon, and even games like WOW and DotA.

Lua has been a great language to learn, and writing Neovim and Hammerspoon plugins feels great. However, it still feels a bit rough around the edges compared to something like JavaScript: even simple things like map() don’t have native equivalents in Lua.

I just found we can now write Lua scripts in TypeScript! TypeScriptToLua is a compiler that can do exactly what its name says it can do.

Written by Rico Sta. Cruz

I am a web developer helping make the world a better place through JavaScript, Ruby, and UI design. I write articles like these often. If you'd like to stay in touch, subscribe to my list.


More articles

← More articles