@danielkelly_io

@danielkellyio

Alabama, USA

Daniel Kelly

Lead Instructor @ Vue School

Full Stack developer (10 years)

Husband and Father

presentation Icons from fontawesome.com

Leveling Up Nuxt

Nuxt 2 → Nuxt 3

Vue

Vue

Dynamic/Reactive Frontends

<template>
  <div>
    <h1>Nuxt is Awesome!</h1>
    <ul v-auto-animate>
      <li 
        v-for="reason in soManyReasons" 
        :key="reason">
        {{ reason }}
      </li>
    </ul>
  </div>
</template>

Templating

v2

Vue

3

Vue

3

Increased Performance

  • ~55% faster overall
  • updates up to 33% faster
  • memory usage ⬇ 54%

TypeScript Support

  • Improved DX
  • Zero-config
  • Less fragile apps

Composition API

  • Better logic reuse
  • Flexible code organization
  • Better type inference

v3

Universal Rendering

Better Performance

No waiting for browser to

run JS app and render

Improved SEO

Web crawlers directly index

the page's content

Universal Rendering

Static Site Generation

Cheap, fast, secure hosting

on the Jamstack

v2

Better Performance

No waiting for browser to

run JS app and render

Improved SEO

Web crawlers directly index

the page's content

Universal Rendering

Static Site Generation

Cheap, fast, secure hosting

on the Jamstack

New and Improved

💪

Runs Anywhere

Not just Node anymore.

Deno, workers, +

Built for Fast

Cold Starts

Great for serving from

Lambda or Edge Functions

Universal Rendering

Hybrid Rendering

Support multiple

rendering modes on a

single app

v3

Hybrid Rendering

export default defineNuxtConfig({
  routeRules: {
    // Static page generated on-demand, revalidates in background
    '/blog/**': { swr: true },
    // Static page generated on-demand once
    '/articles/**': { static: true },
    // Set custom headers matching paths
    '/_nuxt/**': { headers: { 'cache-control': 's-maxage=0' } },
    // Render these routes with SPA
    '/admin/**': { ssr: false },
    // Add cors headers
    '/api/v1/**': { cors: true },
    // Add redirect headers
    '/old-page': { redirect: '/new-page' },
    '/old-page2': { redirect: { to: '/new-page', statusCode: 302 } }
  }
})

v3

Hybrid Rendering

v3

Zero-Config Deploys

Or minimal config deploys

v3

Tooling

Webpack

Bundling and

development server

with HMR

CLI

Start dev server, build for production, ssg

v2

Tooling

Vite

Lightning fast

development server

with HMR

Nuxi CLI

Everything from Nuxt CLI

plus: file scaffolding, updates,

cleanup, and more!

v3

Tooling

File Structure

File Structure

Conventions

Predictable file structure

that's easy to navigate

Functionality Based

on Directory

Auto imported components,

file-based routing, etc

v2

File Structure

Conventions

Predictable file structure

that's easy to navigate

Functionality Based

on Directory

Auto imported components,

file-based routing, etc

V3 Enhancments

Nuxt 3 adds conventions

and added functionality

v3

routes created based on structure (including dynamic routes)

/pages

/pages/edit-[id].vue

v2

/pages/_id.vue

Dynamic Params

/pages/[id].vue

v3

Dynamic Params

/pages/_.vue

Catch All

/pages/[...slug].vue

Catch All

<NuxtLink to="/123">Post 123</NuxtLink>

routes created based on structure (including dynamic routes)

/pages

v3

Page Meta

// MyPage.vue
definePageMeta({  
  middleware: ["auth"],
  pageTransition: 'fade',
  layout: 'blog',
})
useHead({
  title: "Hello World"
})

v2

Page Meta

// MyPage.vue
export default {
  middleware: 'auth',
  transition: 'fade',
  layout: 'blog',
  head() {
    return {
      title: 'Hello World',
    }
  }
}

predictable location to store Vue Single File components

/components

v3

Auto Imports


// it's automatic!

v2

Auto Imports

// nuxt.config.js
export default {
  components: true
}

🔥 so are composables!

/composables

predictable location to store Vue Single File components

/components

v3

Client Only

// MyPage.vue
<template>
  <ClientOnly>
    <MyComponent/>  
  </ClientOnly>
</template>

v2

Client Only

// MyPage.vue
<template>
  <ClientOnly>
    <MyComponent/>  
  </ClientOnly>
</template>

predictable location to store Vue Single File components

/components

v2

Client Only

// MyPage.vue
<template>
  <ClientOnly>
    <MyComponent/>  
  </ClientOnly>
</template>

v3

Client Only

// MyPage.vue
<template>
    <MyComponent/>  
</template>

MyComponent.client.vue

MyComponent.server.vue

predictable location to store Vue Single File components

/components

MyComponent.client.vue

v2

Client Only

// MyPage.vue
<template>
  <ClientOnly>
    <MyComponent/>  
  </ClientOnly>
</template>

v3

Client Only

// MyPage.vue
<template>
    <MyComponent/>  
</template>

// MyComponent.server.vue
<template>
  Loading...
</template>

MyComponent.server.vue

MyComponent.client.vue

predictable location to store Vue Single File components

/components

MyComponent.client.vue

v2

Client Only

// MyPage.vue
<template>
  <ClientOnly>
    <MyComponent/>  
  </ClientOnly>
</template>

v3

Client Only

// MyPage.vue
<template>
    <MyComponent/>  
</template>

// MyComponent.client.vue
<script setup>
  $fetch("http://myapi.com")
</script>

MyComponent.client.vue

lazy load components by prefixing with "lazy"

/components

<LazyMountainsList v-if="show" />
  • useful if component is not always needed
  • delay loading component until the right moment
  • optimize bundle size

combine directory structure to assemble component name

/components

(Duplicate segments are removed)

 <BaseFooCustomButton />

extract common UI or code patterns into reusable layouts

/layouts

v3

Render Page

// layouts/default.vue
<template>
  <div>
    <slot />
  </div>
</template>

v2

Render Page

// layouts/default.vue
<template>
  <Nuxt />
</template>

⚠️ must provide wrapper!

extract common UI or code patterns into reusable layouts

/layouts

v3

Render Page

// ~/error.vue
<template>
  <pre> {{error}} </pre>
</template>

<script setup>
defineProps({
  error: Object
})
</script>

v2

Error Page

// layouts/error.vue
<template>
  <pre> {{error}} </pre>
</template>

<script>
export default {
  props: ['error'],
}
</script>

run code before navigating to a route

/middleware

  • anonymous middleware
  • named middleware
  • global middleware

run code before navigating to a route

/middleware

v2

Global Middleware

// nuxt.config.js
export default{
  router: {
    middleware: 'log',
  },
}

~/middleware/log.js

v3

Global Middleware

~/middleware/log.global.js

run code before navigating to a route

/middleware

v2

Middleware Definition

// middleware/log.js
export default function (context) {
  console.log("hello")
}



v3

Middleware Definition

// middleware/log.js
export default defineNuxtRouteMiddleware((to, from) => {
  console.log("hello")
})

run code before navigating to a route

/middleware

v2

Middleware Definition

// middleware/log.js
export default function ({redirect}) {
  return redirect("/login")
}

v3

Middleware Definition

// middleware/log.js
export default defineNuxtRouteMiddleware((to, from) => {
  return navigateTo('/login')
})

provide global helpers, register Vue plugins and directives

/plugins

v2

Register Plugins

// nuxt.config.js
export default {
  plugins: ['~/plugins/tooltip.js']
}

v3

Register Plugins

🔥 auto registered!

provide global helpers, register Vue plugins and directives

/plugins

v2

Register Vue Plugin

// ~/plugins/tooltip.js

import Vue from 'vue'
import VTooltip from 'v-tooltip'

Vue.use(VTooltip)

v3

Register Vue Plugin

// ~/plugins/tooltip.js
import VTooltip from 'v-tooltip'

export default defineNuxtPlugin((nuxtApp) => {
  nuxtApp.vueApp.use(VTooltip)
})

provide global helpers, register Vue plugins and directives

/plugins

v2

Register Vue Plugin

// ~/plugins/tooltip.client.js

import Vue from 'vue'
import VTooltip from 'v-tooltip'

Vue.use(VTooltip)

v3

Register Vue Plugin

// ~/plugins/tooltip.client.js
import VTooltip from 'v-tooltip'

export default defineNuxtPlugin((nuxtApp) => {
  nuxtApp.vueApp.use(VTooltip)
})

provide global helpers, register Vue plugins and directives

/plugins

v2

Global Helpers

// ~/plugins/tooltip.js

export default ({ app }, inject) => {
  inject(
    'hello', 
    msg => console.log(`Hello ${msg}!`)
  )
}

v3

Global Helpers

// ~/plugins/tooltip.js
export default defineNuxtPlugin(() => {
  return {
    provide: {
      hello: (msg: string) => `Hello ${msg}!`
    }
  }
})

provide global helpers, register Vue plugins and directives

/plugins

v2

Global Helpers

// MyComponent.vue
<template>  
  <div>{{ $hello('world') }}</div>
</template>

v3

Global Helpers

// MyComponent.vue
<template>  
  <div>{{ $hello('world') }}</div>
</template>

provide global helpers, register Vue plugins and directives

/plugins

v2

Global Helpers

// MyComponent.vue
<script>
export default {
  created() {
    this.$hello('mounted')
  }
}
</script>

v3

Global Helpers

// MyComponent.vue

<script setup lang="ts">
const { $hello } = useNuxtApp()
</script>

Just use a composable 🤔

Other miscellaneous changes made to the file structure

File Structure Misc.

v2

Static Assets

v3

Static Assets

Other miscellaneous changes made to the file structure

File Structure Misc.

v2

State Management

const useX = () => useState('x')

State Management

v3

Other miscellaneous changes made to the file structure

File Structure Misc.

v2

Server Directory

🤷

v3

Server Directory

REST api routes

runs on every request (including api)

nitro plugins

Currently available resources

Migrate from 2 to 3

Progressively migrate with this compatibility layer for Nuxt 2

Nuxt Bridge

  • Nitro
  • Vite
  • Composition API
  • Script Setup
  • Auto Imports

Nuxt 3 Fundamentals

Premium Vue Courses

855 lessons • 71 Hours • 45 Courses

51% OFF Black Friday Sale

Plus a FREE workshop!

@danielkelly_io

@danielkellyio

Alabama, USA

Thanks!

Leveling Up Nuxt (2->3)

By Daniel Kelly

Leveling Up Nuxt (2->3)

  • 986