Suffixes, Prefixes, and Nuxt Magic: A Developer’s Guide to Smart Coding

In Nuxt, prefixes and suffixes might seem like small details, but they play a pivotal role in shaping how components, plugins, and middleware are structured and used. These naming conventions bring clarity, control, and optimised performance to your application by influencing how and when specific parts of your code run. From controlling client-side and server-side behaviour to lazy loading and custom configurations, mastering prefixes and suffixes can make a significant difference in your project's functionality and performance. This guide will walk you through the essential prefixes and suffixes in Nuxt, explore what they do and the ways they can streamline your development process.

These small details can easily get overlooked in the documentation, so here’s a comprehensive overview of all the prefixes and suffixes in Nuxt.

Suffixes:

.global.ts (Route Middleware):

The .global.ts suffix is used for defining global route middleware in Nuxt. Middleware is an essential concept in Nuxt that allows you to run specific logic before rendering a page or route. A .global.ts file typically contains global middleware that executes before every route change, allowing you to set up things like authentication checks, global error handling, or logging.

  • Example: A auth.global.ts could be a global middleware to check for user authentication before any route is accessed.
    export default defineNuxtRouteMiddleware((to, from) => {
      const user = useAuth()
      if (!user.isAuthenticated && to.name !== 'login') {
        return navigateTo('/login')
      }
    })
    

.server.vue (Vue Components, Nuxt Pages):

The .server.vue suffix indicates Vue components that will be rendered on the server side only. This is part of Nuxt’s hybrid rendering model, where certain components can be server-rendered to improve performance, especially for SEO-sensitive content. These components are not shipped to the client, meaning they are used only for server-side rendering (SSR) purposes.

  • Example: You can use this for content that should be indexed by search engines but doesn’t need interactivity on the client side, such as static blog content or meta information.
    <!-- components/HighlightedMarkdown.server.vue --> 
    <template>
      <div v-html="renderedMarkdown"></div>
    </template>
    
    <script setup>
    import MarkdownIt from 'markdown-it'
    
    const props = defineProps({
      content: {
        type: String,
        required: true,
      },
    })
    
    const md = new MarkdownIt()
    const renderedMarkdown = md.render(props.content)
    </script>
    

.client.vue (Vue Components, Nuxt Pages):

Conversely, the .client.vue suffix denotes that a component should be rendered only on the client side. This is useful when you have dynamic components that rely heavily on client-side JavaScript (such as components with complex interactions like maps or charts) and don’t need server-side rendering.

  • Example: An interactive map component for a web app that relies on user interactions and doesn't need server-side rendering.
    <template>
      <div>
        <!-- Only rendered on the client-side -->
        <MapComponent />
      </div>
    </template>
    

.global.vue (Vue Components):

In addition to controlling whether components render on the client or server, Nuxt allows components to be registered globally, making them accessible throughout the application. This global registration is particularly useful when you want components to be available in multiple places, such as within markdown files or across various views, without needing to import them each time.

There are two main methods for globally registering Vue components in Nuxt. First, you can place your component files inside the ~/components/global directory, which Nuxt automatically scans and registers. Alternatively, you can add the .global.vue suffix to your component file name, enabling Nuxt to treat it as a globally accessible component. These approaches simplify component management and streamline your code, especially when working with reusable components across your project.

.server.ts (Plugins):

The .server.ts suffix refers to server-side-only plugins in Nuxt. Plugins in Nuxt can inject additional functionality into your application (such as external libraries, API calls, etc.). When you define a plugin with .server.ts, it will only run during server-side rendering, making it useful for logic that needs to stay on the server (like sensitive API calls or fetching data during SSR).

  • Example: A plugin that fetches data from a database during the server-side rendering process.
    export default defineNuxtPlugin(() => {
      // Server-only logic here
      return {
        provide: {
          fetchData: async () => { /* fetch data server-side */ }
        }
      }
    })
    

.client.ts (Plugins):

The .client.ts suffix is for client-side plugins, which are loaded only on the client. This is useful for logic or libraries that require access to the browser’s APIs (such as local storage, window, or document objects), which are unavailable on the server.

  • Example: A plugin that integrates a client-side-only library, such as icon libraries, web analytics tools or browser-based features.
    // plugins/vue-gtag.client.ts
    import VueGtag, { trackRouter } from 'vue-gtag-next'
    
    export default defineNuxtPlugin((nuxtApp) => {
      nuxtApp.vueApp.use(VueGtag, {
        property: {
          id: 'GA_MEASUREMENT_ID'
        }
      })
      trackRouter(useRouter())
    })
    

HTTP Method Suffix (Nitro):

Although Nuxt doesn’t enforce this, it’s considered good practice to suffix API endpoint files with the corresponding HTTP method. For instance, naming a file users.get.ts or user.post.ts clearly indicates the file’s purpose and HTTP method, improving readability and organisation across your codebase.

It also minimises potential confusion when working with endpoints that might perform similar functions but require different HTTP methods, such as GET, POST, PUT, or DELETE.

  • Examples:
// server/api/test.get.ts
export default defineEventHandler(() => 'Test get handler')
// server/api/test.post.ts
export default defineEventHandler(() => 'Test post handler')

Adopting this convention can make your codebase cleaner, easier to navigate, and more manageable, especially as your API grows in complexity.

Prefixes:

Lazy (Components):

In Nuxt, the Lazy prefix is used to defer the loading of certain components or resources. Lazy loading improves the performance of an application by only loading components when they are required, such as when they are visible on the screen. This is especially useful for reducing initial load times on larger applications.

  • Usage: You can use lazy loading for components, which allows parts of the application to load only when necessary, rather than on initial page load.
  • Example in Nuxt:
    <!-- pages/index.vue -->
      <script setup lang="ts">
      const show = ref(false)
      </script>
    
      <template>
        <div>
          <h1>Mountains</h1>
          <LazyMountainsList v-if="show" />
          <button v-if="!show" @click="show = true">Show List</button>
        </div>
      </template>
    
    • This technique is useful for optimising page load times and minimising the amount of JavaScript the browser has to process initially.
  • Nuxt auto imports Lazy prefix: If you’re using auto-import functionality, Nuxt automatically manages lazy loading with the Lazy prefix, making it easier to handle large projects.

Custom Prefixes (Components):

When adding extra directories or subdirectories of components for auto-import scanning, we can customise the configuration further. For example, we can include a prefix key to define a prefix for the components.

By default, component names incorporate their file path for usage. For instance, a component located at components/event/Update.vue is used as <EventUpdate />. Nuxt offers a configuration option, pathPrefix, which accepts a boolean value to disable this default behaviour.

  • Example:
  export default defineNuxtConfig({
    components: [
      // ~/components/admin-components/Btn.vue => <AdminBtn />
      { path: '~/components/admin-components', prefix: 'Special' },

      // ~/calendar-module/components/event/Update.vue => <EventUpdate />
      { path: '~/calendar-module/components' },

      // ~/user-module/components/account/UserDeleteDialog.vue => <UserDeleteDialog />
      { path: '~/user-module/components', pathPrefix: false },
    ]
  })

More on Lazy

While discussing Lazy, it’s worth noting that Nuxt has a few additional "lazy" features. Though they aren’t technically suffixes or prefixes, they’re still valuable to mention.

Lazy Data Fetching

When using useFetch, Nuxt waits for the asynchronous function to resolve before navigating to a new page. To prevent this on the client side, you can set lazy: true.

Example:

<script setup lang="ts">
const { status, data: posts } = useFetch('/api/posts', {
  lazy: true
})
</script>

This behaviour applies to useAsyncData as well. Alternatively, Nuxt offers useLazyFetch and useLazyAsyncData as convenient shortcuts to achieve the same effect.

Example:

<script setup lang="ts">
const { status, data: posts } = useLazyFetch('/api/posts')
</script>

Lazy Nuxt Island

The lazy prop in the NuxtIsland component enables lazy loading for sections of your page where the NuxtIsland component is used. When lazy is set to true, the component delays its loading until it comes into view or when other user-defined conditions are met.

Lazy Nuxt Img

The loading attribute is a native HTML property that guides the browser on how to load an image. By setting loading="lazy", the image's loading is deferred until it appears within the viewport.

Example:

<NuxtImg src="/nuxt-icon.png" loading="lazy" />

By understanding and effectively using prefixes and suffixes in Nuxt, you can take greater control over how components and plugins are handled in your application. Whether optimising loading times with lazy prefixes or defining server-side and client-specific logic, these conventions empower developers to build more efficient and organised code. With a few thoughtful configurations, you’ll make your Nuxt applications not only more performant but also easier to maintain and expand. So, as you continue developing with Nuxt, keep these powerful conventions in mind to maximise both productivity and performance.

Related Content