NUXT 3: How to use route middleware in a layout? (Can I?)
Asked Answered
I

6

8

I've been looking to use Nuxt middleware in a layout. But I am not sure if I even can, however, since I used it in Nuxt 2, it may be possible in Nuxt 3.

The project has 2 different layouts: Public.vue and Admin.vue. I only want to use the middleware in pages that consume the Admin layout. Because the pages that use it should be accessed only by logged-in users, and it will be checked inside the middleware.

I tried this (doesn't work):

Admin layout | Admin.vue

<template>
  <div>
    <client-only>
      <admin-header />
    </client-only>
    <main>
      <slot />
    </main>
    <client-only>
      <admin-footer />
    </client-only>
  </div>
</template>

<script lang="ts">
import AdminHeader from "~~/components/admin/Header.vue"
import AdminFooter from "~~/components/admin/Footer.vue"

definePageMeta({
  middleware: "admin-auth"
});
</script>

Middleware | adminAuth.ts

export default defineNuxtRouteMiddleware((to, from) => {
    console.log(to);
    console.log("Acessando o admin auth middleware");
})
Impious answered 9/8, 2022 at 14:15 Comment(1)
Is your file in middleware directory? Maybe try to name it admin-auth, not sure if this may help. This seems to work pretty well: v3.nuxtjs.org/examples/routing/middleware But yeah, client side middleware is feasible.Nitre
C
14

You cant. Middleware only works for pages.

Instead, make a parent Page component with the auth middleware and NuxtPage component inside the template. See the Nuxt 3 docs for more information on nested routes.

Example:

/pages/admin.vue (route => /admin)

<template>
  // you can add auth based components as well
  <NuxtPage />
</template>

<script setup lang="ts">
  definePageMeta({
     middleware: "admin-auth"
  });
</script>

/pages/admin (folder)

All other components inside admin folder will use your auth middleware

admin/order.vue route => /admin/orders

admin/page.vue route => /admin/some-route

Clemmie answered 2/9, 2022 at 19:3 Comment(5)
Hm, I'm pretty sure that you can apply a middleware to a layout.Nitre
let me know how it is possible pleaseClemmie
You are right. After some research, I found the same answer but forgot to write here. That's a shame...Impious
how to call global middlewares?Tolidine
<NuxtChild /> is not used in Nuxt 3. See: nuxt.com/docs/migration/pages-and-layouts#migration-2Thermograph
C
10

It is not possible to use middleware in layout because middleware only can be use in pages, but you can try to use this method.

Create a global middleware by declaring .global suffix after your middleware file name for example auth.global.ts.

In auth.global.ts file you can use layout meta as your logic to simulate as if the middleware is in your layout setup.

Sample logic is like this

export default defineNuxtRouteMiddleware((to, from) => {
    const user = useUserStore();
    
    if (!user && to.meta.layout === auth) {
        return navigateTo("/login");
    }
});

Hope this helps

Casseycassi answered 9/12, 2022 at 17:52 Comment(1)
to.meta.layout is a string, so needs to be === 'auth'Foreworn
S
2

You can use the .global to the middleware for it to apply to all pages. so change your filename to /middleware/adminAuth.global.ts

See here https://nuxt.com/docs/guide/directory-structure/middleware

Substitution answered 2/11, 2022 at 21:2 Comment(0)
P
0

Added a file called router.global.ts

added to /src/middleware/router.global.ts

router.global.ts content:

export default defineNuxtRouteMiddleware((to) => {
    if (to.fullPath.includes('+')) to.fullPath = to.fullPath.replace(/\+/g, '%20');
});

nuxt.config.ts add:

router: {
     middleware: ['router'],
},
Presentation answered 31/3, 2023 at 18:8 Comment(0)
K
0

Ok, i was personally struggling with the layoutTransition { name }, i discovered a possibility to set it using the useRoute() like this:

<script setup lang="ts">
import { ref, nextTick } from "vue";

definePageMeta({
  layout: "lay1",
  layoutTransition: {
    name: "slide-left",
  },
});

const sw = () => {
  const route = useRoute();

  if (route.meta.layout === "lay2") {
    route.meta.layoutTransition = { name: "slide-left" };
    nextTick(() => {
      setPageLayout("lay1");
    });
  } else {
    route.meta.layoutTransition = { name: "slide-right" };
    nextTick(() => {
      setPageLayout("lay2");
    });
  }
};
</script>
Ketene answered 27/8, 2023 at 13:20 Comment(0)
A
0

I had problems with auth.global.ts been render on server side. So I put a client side validation and a trick ({ external: true }) on navigateTo redirect (because redirect to page with diferent layout cause style bugs):

export default defineNuxtRouteMiddleware((to, from) => {

    if (process.client) {
        const user = UtilsUser.user //Get from localStorage.getItem('user')

        if (!user && to.meta.layout === 'profile') {
            //Prevent Loop:
            if (to.path !== '/auth/login') {
                return navigateTo('/auth/login', { external: true })
            }
        }
    }

})
Advisement answered 17/3 at 20:54 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.