The Web's Next Transition

Kent C. Dodds

Where we came from, where we are, and where we're going.

Let's wake up

Your brain needs this 🧠

What this talk is

  • A journey through time as a web dev
  • Forward looking
  • A bit of a game

What this talk is not

  • Comprehensive

Let's
Get
STARTED!

<a href="/profile">Your Profile</a>


<form method="post" action="/edit/profile">
  <label>
    Username: <input name="username" />
  </label>
  <button type="submit">Submit</button>
</form>
  • Multi-Page Apps (MPA)
  • Progressively Enhanced Multi-Page Apps (PEMPA)
  • Single Page Apps (SPA)
  • The Next Transition

Web Architectures

Follow the code

  • Persistence
  • Routing
  • Data fetching
  • Data mutation
  • Rendering logic
  • UI Feedback

Multi-Page Apps (MPA)

Pros

  1. Simple mental model
  2. Only way to do it 😅

Cons

  1. Full-page refresh
  2. Lack of UI feedback control

Multi-Page Apps (MPA)

Progressively Enhanced Multi-Page Apps (PEMPA)

Pros

  1. No more refreshes
  2. UI Feedback control

Cons

  1. Prevent default
  2. Amount of custom code
  3. Code duplication
  4. Code organization
  5. Server/Client indirection

Progressively Enhanced Multi-Page Apps (PEMPA)

Single Page Apps (SPA)

Pros

  1. No code duplication

Cons

  1. Most of PEMPAs Cons
  2. Bundle size
  3. Waterfalls
  4. Runtime performance
  5. State management

Single Page Apps (SPA)

Are you ready for the Web's Next Transition?

Introducing the PESPA!

Progressively Enhanced Single Page Apps

Progressively Enhanced Single Page Apps (PESPA)

Pros

  1. Simple mental model
  2. No full-page refresh
  3. UI Feedback control
  4. Browser emulation
  5. No code duplication
  6. Reduced client-side JS
  7. No waterfalls
  8. No application state management

Cons

  1. Requires servers
  2. Server cost
  3. Universal code
  4. We will certainly discover more...

Progressively Enhanced Single Page Apps (PESPA)

?

PESPA Implementation:

// app/routes/projects.tsx
export async function loader({ request }: DataFunctionArgs) {
  const projects = await getProjects()
  return json({ projects })
}

export async function action({ request }: DataFunctionArgs) {
  const form = await request.formData()
  const error = validateProjectForm(form)
  if (error) return json({ error }, { status: 400 })

  const project = await createProject({ title: form.get('title') })
  return redirect(`/projects/${project.id}`)
}

export default function Projects() {
  const projects = useLoaderData<typeof loader>()
  const actionData = useActionData<typeof action>()
  const { state } = useNavigation()
  const busy = state === 'submitting'

  return (
    <div>
      <h1>Projects</h1>
      <ul>
        {projects.map(project => (
          <li key={project.id}>
            <Link to={project.slug}>{project.title}</Link>
          </li>
        ))}
      </ul>

      <Form method="post">
        <label>
          New Project Title: <input name="title" />
        </label>
        {actionData?.error ? <p>{actionData.error}</p> : null}
        <button type="submit" disabled={busy}>
          {busy ? 'Creating...' : 'Create New Project'}
        </button>
      </Form>
    </div>
  )
}

Resources

You belong here

Thank you!