In early 2019, I deconstructed and organised Nuxt 2 context
keys on an A4 page for Nuxt 2.0. This is one of my most liked Nuxt 2 diagrams to date ❤️.
Context keys are huddled up in this single-page reference guide of Nuxt essential ✍️ - one of my favourite features of @nuxt_js. Follow the colours & lines and it’ll all come together.#nuxtjs #vuejs #javascript pic.twitter.com/tXuTJEpKIR
— Krutie Patel (@KrutiePatel) February 27, 2019
context
keys provide additional information that we may need while working with components, plugins, route middleware or even composable now that the Vue 3 is the new default version.
If you have been using Nuxt for a while now, you may be curious about what happened to the Nuxt 2 context
object in Nuxt 3.
Nuxt 2 context is still available, ...but only as a part of Nuxt 2 Bridge composition API. However, it is not recommended to use Nuxt 2 context
, because it will not exist in Nuxt 3. This means that we are not going to have a single context
object in Nuxt 3. After doing some research, I have learned that we have a collection of composable and utility functions - available in Nuxt 3 by default - that can help us access similar information.
Below is the high-level list of information that we are used to accessing from Nuxt context
.
Let's see where we can find them in Nuxt 3 along with quick code samples for reference.
In Nuxt 2, we add an env
object in nuxt.config
that normally includes all environment variables. We then access those variables in the Nuxt context
through the env
key.
// Nuxt 2
// nuxt.config.js
export default {
env: {
baseUrl: process.env.BASE_URL || 'http://localhost:3000'
}
}
From v2.13
, Nuxt introduced runtimeConfig
to define environment variables, and $config
key to access those variables.
Starting from Nuxt 3, we can completely rely on runtimeConfig
to define both public
and private
runtime environment variables.👇
// nuxt.config.ts
import { defineNuxtConfig } from 'nuxt'
export default defineNuxtConfig({
runtimeConfig: {
// Private config that is only available on the server
UPSTASH_REDIS_REST_URL: process.env.UPSTASH_REDIS_REST_URL,
UPSTASH_REDIS_REST_TOKEN: process.env.UPSTASH_REDIS_REST_TOKEN,
// Config within public will be also exposed to the client
public: {
baseUrl: process.env.BASE_URL || 'http://localhost:3000'
}
},
})
We can then access these environment variables directly by using useRuntimeConfig
composable on both client-side and server-side.
// server/api/count.ts
import { auth } from '@upstash/redis';
const config = useRuntimeConfig()
auth(config.UPSTASH_REDIS_REST_URL, config.UPSTASH_REDIS_REST_TOKEN);
In Nuxt 2, we have an error
function that handles errors on both client-side and server-side.
// Nuxt 2
error({
message: 'Page not found',
statusCode: 404
})
In Nuxt 3, three key stages of error handling are divided into individual helper methods:
useError
throwError
clearError
useError
returns global Nuxt error details, such as statusCode
and message
, that is being handled.
// error.vue
<script setup>
// customise 404 message from script section
const error = useError();
if (error.value.statusCode === 404) {
error.value.message = 'Oops! Page not found 😔';
}
</script>
As per Nuxt convention, we use error.vue
to create a custom error page for our Nuxt application.
Back in Nuxt 2, we put error.vue
inside /layout
directory. But now in Nuxt 3, we can put error.vue
directly in the root of the project.
throwError
triggers a full-screen error page and can be called on both client-side or on server-side directly using:
setup()
functions.// plugins/my-plugin.ts
export default defineNuxtPlugin((nuxtApp) => {
const config = useRuntimeConfig()
nuxtApp.hook("vue:error", () => {
return throwError("error in vue:error");
});
nuxtApp.hook("app:error", () => {
return throwError("error in app:error");
});
nuxtApp.vueApp.config.errorHandler = (error) => {
return throwError("global error handler");
};
});
As the name suggests, clearError
clears the current Nuxt error that's being handled.
clearError
also takes an optional parameter - redirect
- to redirect users to a different page if required.
<template>
<!-- Redirect to home page -->
<button @click="handleError">Clear errors</button>
</template>
<script setup>
// clear error and redirect to home page
const handleError = () => clearError({ redirect: '/' });
</script>
In Nuxt 2, we have to create /store
directory and add index.js
to activate Vuex store in Nuxt application like below 👇
// store/index.js
export const state = () => ({
counter: 0
})
With Nuxt 3, we have two options to manage state.
useState
- This composable is provided by Nuxt 3 itself for application-wide state management.// set color state
const useColor = () => useState<string>('color', () => 'pink')
// access color state
const color = useColor()
// update color state
const color = useColor()
color.value = 'purple'
useState
and Pinia for your application.
In Nuxt 2, res
and req
objects are available through the context
object only on server-side.
// Nuxt 2
function (context) {
if (process.server) {
const { req, res } = context
}
}
In Nuxt 3, we have a couple of options to access the incoming request as below.
useRequestEvent
composable, oruseNuxtApp.ssrContext
composableWe can use useRequestEvent
composable in:
// Get underlying request event
const event = useRequestEvent()
// Get the URL
const url = event.req.url
Since the incoming request is only accessible on server-side, useRequestEvent
will return undefined
on client-side.
Alternatively, we can also use useNuxtApp
composable to access res
and req
objects for the current request.
We can access the incoming request here through ssrContext
which is a part of useNuxtApp
composable.
const nuxtApp = useNuxtApp()
const { ssrContext } = nuxtApp
Inside ssrContext
, we can access http req
and res
.
const host = ssrContext.event.req.headers.host
ssrContext
is available to use on server-side, in:
📍 Always be sure to check the process.server
condition before accessing the ssrContext
.
// pages/index.vue | app.vue | components/component.vue
<script lang="ts">
export default defineComponent({
async setup() {
const NuxtApp = useNuxtApp();
if (process.server) {
const { ssrContext } = NuxtApp
}
}
});
</script>
In Nuxt 2, the route
object is available through Nuxt context
on both server-side and client-side.
In Nuxt 3, we have useRoute
composable that returns the current route including route parameters and query parameters, if applicable.
useRoute
must be called in:
setup
function,// pages/posts/[slug].vue
<script setup>
const route = useRoute()
const slug = route.params.slug
const { data: mountain } =
await useFetch(`https://api.nuxtjs.dev/mountains/${slug}`)
</script>
<template>
<div>
<h1>{{ mountain.title }}</h1>
<p>{{ mountain.description }}</p>
</div>
</template>
In Nuxt 2 context, app
is available as the global instance of the Vue application.
This root Vue instance includes all your client-side plugins. For example, when using i18n
, you can get access to $i18n
through context.app.i18n
.
In Nuxt 3, the same global Vue instance can be accessed through useNuxtApp
composable.
const { nuxtApp } = useNuxtApp()
// nuxtApp.vueApp
We can use vueApp
to create Nuxt plugin that adds Google Analytics - vue-gtag - in Nuxt 3 application.
// Nuxt 3
// plugins/vue-gtag.client.js
import VueGtag from 'vue-gtag-next'
export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.vueApp.use(VueGtag, {
property: {
id: 'GA_MEASUREMENT_ID'
}
})
})
nuxtApp.vueApp
.We do have access to all Vue router methods, such as back
, forward
, go
, push
and replace
through useRouter
composable.
Yet Nuxt 2 context
provides a handy function called redirect
that is available on both client-side and server-side. The redirect
function helps programmatically navigate users to another route.
In Nuxt 3, we have a new utility function, called navigateTo
, that works the same as the redirect
function - on both server-side and the client-side.
// Nuxt 3
navigateTo({
path: '/search',
query: {
name: name.value,
type: type.value
}
})
navigateTo
takes two optional parameters, replace
and redirectCode
.
On the client-side, navigateTo
function is a wrapper around two popular Vue router methods, router.replace
and router.push
.
Optional parameter replace
is used on client-side to determine whether to replace
the route or push
the route.
await navigateTo('/', { replace: true })
On server-side, navigateTo
uses sendRedirect
function provided by h3
to handle redirection on the server-side.
sendRedirect(res, location, code=302)
Optional parameter redirectCode
is used on the server-side, and it defaults to 302
.
We can access navigateTo
function in:
The example below shows how we can redirect a user to the login page if the user is not authenticated.
// [Nuxt 3]
export default defineNuxtRouteMiddleware((to, from) => {
const auth = useState('auth')
if (!auth.value.authenticated) {
return navigateTo('/login')
}
})
In Nuxt 2, we have access to beforeNuxtRender
function on server-side. Then, using nuxtState
on the client-side, we can pass data from server-side to client-side as below.
// Nuxt 2
// plugins/my-plugin.js
export default ({ beforeNuxtRender, nuxtState }) => {
if (process.server) {
beforeNuxtRender(({ nuxtState }) => {
nuxtState.color = 'pink'
})
} else {
console.log('Custom data on the client side:', nuxtState.color)
}
}
useState
section was updated on 22 May 2023.
In Nuxt 3, the same plugin can be rewritten using useState
.
// Nuxt 3
// plugins/my-plugin.server.ts
export const useColor = () => useState<string>('color', () => 'pink')
export default defineNuxtPlugin((nuxtApp) => {
const color = useColor()
})
📍 Since we are setting server-side data to be accessed on client-side, always be sure to check the process.server
condition before setting the data.
📍 we can add .server
postfix to make sure the Nuxt plugin runs only on the server-side.
As in for accessing this custom data on the client-side, we can use useState
composable along with the key, i.e. color
to access the data.
// useColor composable
const color = useState('color')
// console.log(color.value) // 'pink'
In Nuxt 2 context, we have access to isDev
, and even before that, in older versions of Nuxt, we had access to variables like, isServer
and isClient
.
These variables don't seem to be available in any of the existing composable of Nuxt 3 at the moment.
But if we think in terms of composable, then we can use useState
to our advantage and expose required server-side information on the client-side.
In the example 👇, I have used useState
to expose isDev
and isClient
variables on the client-side.
// plugins/variables.server.ts
export const useGlobalVariables = () => useState<object>('globalVariables', () => {
return {
isDev: process.env.NODE_ENV !== 'production',
isClient: process.client,
}
})
export default defineNuxtPlugin((nuxtApp) => {
const globalVariables = useGlobalVariables()
})
Same as the previous example, for accessing these variables on the client-side, we can use useGlobalVariables
key along with the useState
composable.
// useColor composable
const globalVar = useState('useGlobalVariables')
// console.log(globalVar.value)
When we console these values, they will reflect their respective environment. For example, isClient
value will be false
in terminal, and true
in Browser console.
Here's the summary of all the key information that Nuxt 2 context
provided with respective composable or utility functions can help us access the same information with a lot more flexibility than before.
If you like to learn how to create educational concept diagrams like the one you see in this post, check out my articles on how to get started with your diagramming journey.
Follow me @krutiepatel to get notified of my upcoming content.