vue-a11y / vue-axe-next

Accessibility auditing for Vue.js 3 applications using axe-core
https://vue-axe-next.surge.sh/
MIT License
54 stars 3 forks source link

Nuxt 3 compatibility #9

Open CKGrafico opened 2 years ago

CKGrafico commented 2 years ago

Hello is this compatible with Nuxt 3? I tried to create a nuxt plugin like this, but without results:

import { defineNuxtPlugin } from "#app";

export default defineNuxtPlugin(async (nuxtApp) => {
  if (process.env.NODE_ENV === "development") {
    const VueAxe = await import("vue-axe");
    nuxtApp.vueApp.use(VueAxe.default);
  }
});
mariappan-subramanian commented 2 years ago

Any update on this? Would be helpful if there is a guide/example similar to this - https://axe.vue-a11y.com/guide/#nuxt-js @ktquez

alkstal commented 2 years ago

Create a client side plugin, vue-axe.client.ts

import vueAxe from 'vue-axe';

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

Then you need to render the popup component somewhere in your app for it to display, in a root component or a layout perhaps?

<script setup lang="ts">
import { VueAxePopup } from 'vue-axe';
const config = useAppConfig();
const showAxePopup = ref(false);

onMounted(() => {
    showAxePopup.value = config.isDevelopment;
});
</script>

<template>
  /* Other markup excluded... */
  <VueAxePopup v-if="showAxePopup" />
</template>

Make sure you only show it after the component has been mounted, the VueAxePopup causes an error when server-side rendered.

BBoehm commented 1 year ago

When using Nuxt with Vite, this can be further simplefied inside the component:

<script setup lang="ts">
  import { VueAxePopup } from 'vue-axe';
  const showAxePopup = ref(false);

  onMounted(() => {
    showAxePopup.value = import.meta.env.MODE === 'development';
  });
</script>

<template>
  <VueAxePopup v-if="showAxePopup" />
</template>
Djeisen642 commented 1 year ago

I was able to get it to load, but I was not able to get nuxt to ignore it for production builds. Anyone got any ideas for that? I've tried adding it as a dev-only component, and it didn't load the component, but something is still requiring that the package is added to the bundle.

BBoehm commented 1 year ago

Edit: This does not remove it from bundling - see solution from Harm-Nullix below.

@Djeisen642 For me it's really just defining the Plugin and then adding it as described in my last comment (which I just edited, since I needed to move it into the onMounted()).

// plugins/axe.client.ts
export default defineNuxtPlugin((nuxtApp) => {
  nuxtApp.vueApp.use(VueAxe);
});

If that does not work for you, try logging your import.meta.env.MODE - I would expect it to be different on a nuxt dev vs nuxt build (=productive environment).

Harm-Nullix commented 1 year ago

The following setup works fine for me for only included it in development: nuxt.config.ts :

export default defineNuxtConfig({
  vite: {
    optimizeDeps: { include: [...(process.env.NODE_ENV === 'development' ? ['axe-core'] : [])] },
  },
  runtimeConfig: {
    public: {
      env: process.env.NODE_ENV || 'development',
    }
  },
})

plugins/a11y.client.ts :

import { useRawConfig } from '~/frontend/composables/useConfig'

export default defineNuxtPlugin(async (nuxtApp) => {
  const config = useRuntimeConfig()
  if (config.public.env === 'development') {
    // @ts-ignore import has no types
    void import('vue-axe').then((vueAxe) => {
      nuxtApp.vueApp.component('VueAxePopup', vueAxe.VueAxePopup)
      nuxtApp.vueApp.use(vueAxe.default, {
        auto: false,
      })
    })
  } else {
    nuxtApp.vueApp.component('VueAxePopup', h('div'))
  }
})

package.json :

{
  "devDependencies": {
    "axe-core": "4.7.2",
    "nuxt": "3.6.5",
    "vue-axe": "3.1.2",
  },
}

And then just always mount it in app.vue :

<template>
  <nuxt-layout>
    <nuxt-loading-indicator />
    <nuxt-page />
    <vue-axe-popup />
  </nuxt-layout>
</template>