Home / Blog / Nuxt 3 Beta First Impressions
Nuxt 3 Beta First Impressions

Nuxt 3 Beta First Impressions

Daniel Kelly
Daniel Kelly
Updated: May 15th 2022

Nuxt 3 Beta made it's debut on October 12 and I couldn't be more thrilled to give the tires a good kick and take it for a test drive. Here's an overview of some of the cool new features, as well as some of the quirks I've found.

Getting Started

To get started with Nuxt 3 you use the new Nuxt CLI tool nuxi.

npx nuxi init [project-name]

This creates a project that is a lot more bare bones than you're probably used to with Nuxt 2.

nuxt 3 file structure screenshot

Many of the directories you use in Nuxt 2 are still supported but you can build up only the ones you need yourself.

Fast Start-Up

After running npm install you can run npm run dev to spin up the dev environment.

What really impressed me at this step was the speed with which the application started. Hopefully, gone are the days of Nuxt 2's little progress bars in the terminal.

Pages and app.vue

Without the pages directory Nuxt doesn't include Vue Router. This lightens the final bundle for when you don't need Vue Router. Once you add the pages directory though, Vue Router is included and your routes are automatically created for you based on the file structure.

At this point the /app.vue file seems to be optional. If you remove it your page components will behave as expected. If you keep it though, you need to be sure and use the <NuxtPage/> component to insert the proper page component. (I kind of think of like <router-view>.)

// App.vue
<template>
  <div>
    <NuxtPage />
  </div>
</template>

The cool thing about app.vue is that it will be the parent component to all the pages and even all the layouts. Thus if you want anything to show up on all pages of your site even across layouts you could add it to app.vue

// app.vue
<template>
  <div>
        <div>I'm on literally every single page</div>
    <NuxtPage />
  </div>
</template>

That means you could import global styles here if it suites your fancy (or you could continue to do it in nuxt config).

// app.vue
<script>
    import '/assets/style.css'
</script>

Dynamic Routes

Naming page files with dynamic routes in Nuxt 3 is also a bit different. Instead of using an underscore, in Nuxt 3 you use square brackets.

//Nuxt 2
_id.vue

// Nuxt 3
[id].vue

While slightly more verbose the benefit it brings is the ability to have variable text combined with static text in a single piece of the path.

// File: team-[name].vue
// Route: /team-tigers

// $route.params.name === tigers

You can also use dynamic params as directory names.

// File: team/[name]/player/[id].vue
// Route: /team/tigers/player/2

// $route.params.name === tigers
// $route.params.id === 2

The last super cool feature is the ability to make a catch all route by spreading the dynamic param in the filename.

// File: [...slug].vue
// Route: /some/random/route

//$route.params.catchAll === ['some', 'random', 'route']

I was able to utilize this to make a super simple 404 page.

// [...404].vue
<template>
  <div>404 - Page Not Found</div>
</template>

API Routes

The next really awesome feature of Nuxt 3 is the ability to provide ad-hoc api endpoints based on a file existing in the server/api directory. Honestly, it feels a lot like serverless functions and it's refreshing.

You can return a string or any JavaScript data type that is able to be serialized as JSON.

// server/api/hello.ts
export default (req, res) => {
  return {
    msg: 'Hello World'
  }
}

Now making a request to /api/hello will return JSON with the message.

You can combine this with Nuxt 3's useFetch function to provide your application data from the server.

<script setup>
const { data } = await useFetch(
    // api endpoint
    '/api/hello', 

    // options
    {
        method: 'GET'
        params: {},
        baseURL: '',
        // limit data stored in the page payload
        pick:[],
        // fetch data on server side (default true) 
        server: true,
        // load the route before resolving the async function (default false)
        defer: true,
        // transform the data
        transform: value => value
})
</script>

Serverless SSR on Netlify

When it came to deploying the Nuxt 3 application, I was stumped for a moment. I'm typically a static site generation kind of Nuxt user but Nuxt 3 hasn't gotten the SSG functionality up and going yet.

The cool thing though, is that I can still use my favorite hosting provider Netlify but instead of using Nuxt as an SSG, I can deploy it as a SSR application that runs in a serverless environment... and get this: with ABSOLUTELY NO CONFIG! It's amazing! See the Nuxt 3 docs for more info.

Running it as an SSR in a serverless environment keeps it almost as fast as an SSG (though not quite) and means build times can be a lot faster. My little testing site with just a few pages built in 24 seconds.

Store

At this point, Nuxt 3 doesn't seem to support Vuex out of the box. After adding the store directory with an index.js file as in Nuxt 2, I got the following error when trying to access the state on a page:

TypeError: can't access property "state", _ctx.$store is undefined

Instead there's a useState function that can be used within pages, components, and plugins to get and set global state.

// plugins/locale.server.ts
import { defineNuxtPlugin, useState } from '#app'

export default defineNuxtPlugin((nuxt) => {
  const locale = useState(
    'locale',
    () => nuxt.ssrContext.req.headers['accept-language']?.split(',')[0]
  )
})
// MyPage.vue
<script setup>
const locale = useState('locale')
</script>

<template>
  Current locale: {{ locale }}
</template>

Other Interesting Tidbits

I also ran across a few other interesting tidbits along that way that deserve brief mention.

  • Nuxt 3 uses @vueuse/head to manage the document <head> instead of vue-meta
  • Typescript just works! 😎
  • layouts still work mostly the same, plus with some extra flexibility using scoped slots
  • plugins (in the plugins directory) are automatically loaded

A Couple Gotchas

Finally, for a beta release I was really surprised at how little went wrong. That said there were a couple things that tripped me up.

More often than I'd have liked, I had to restart the dev server when adding or removing page component files for the changes to take.

Also, the DevTools didn't work for me at first but I use Firefox so I just had to go re-download the Vue Devtools beta version from the repo and then it was good to go. This was probably on me but thought I'd mention it just in case any of you experience the same.

Conclusion

All in all, I'm super excited about the possibilities of Nuxt 3 and really enjoyed getting behind the wheel and putting the beta version through it's paces. What about you? Have you gotten to play with Nuxt 3 yet? What do you think about it?

If you haven't given it a spin yet, go checkout the new docs and see what you think!

Start learning Vue.js for free

Daniel Kelly
Daniel Kelly
Daniel is the lead instructor at Vue School and enjoys helping other developers reach their full potential. He has 10+ years of developer experience using technologies including Vue.js, Nuxt.js, and Laravel.

Comments

Latest Vue School Articles

From Vue.js Options API to Composition API: Is it Worth it?

From Vue.js Options API to Composition API: Is it Worth it?

Explore the technicalities of transitioning from Options API to Composition API in Vue.js. Discover if migrating your app is worth the effort in our detailed guide
Mostafa Said
Mostafa Said
What’s New in Nuxt 4

What’s New in Nuxt 4

Have anxiety about a new major version of Nuxt coming out? Worried about a big migration project? Don’t worry about it, a peaceful and easy upgrade is literally one of the features of Nuxt version 4.
Daniel Kelly
Daniel Kelly

Our goal is to be the number one source of Vue.js knowledge for all skill levels. We offer the knowledge of our industry leaders through awesome video courses for a ridiculously low price.

More than 200.000 users have already joined us. You are welcome too!

Follow us on Social

© All rights reserved. Made with ❤️ by BitterBrains, Inc.