vue-fontawesome
vue-fontawesome copied to clipboard
Nuxt 3: Hydration mismatch when using SSR
Describe the bug
When using Nuxt 3 with the <font-awesome-icon>
component while using SSR it causes a hydration node mismatch.
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome';
nuxtApp.vueApp.component('font-awesome-icon', FontAwesomeIcon);
Error:
[Vue warn]: Hydration node mismatch:
- Client vnode: svg
- Server rendered DOM: <!---->
at <FontAwesomeIcon icon= Array(2)0: "fal"1: "box-open"length: 2[[Prototype]]: Array(0)at: ƒ at()concat: ƒ concat()constructor: ƒ Array()copyWithin: ƒ copyWithin()entries: ƒ entries()every: ƒ every()fill: ƒ fill()filter: ƒ filter()find: ƒ find()findIndex: ƒ findIndex()findLast: ƒ findLast()findLastIndex: ƒ findLastIndex()flat: ƒ flat()flatMap: ƒ flatMap()forEach: ƒ forEach()includes: ƒ includes()indexOf: ƒ indexOf()join: ƒ join()keys: ƒ keys()lastIndexOf: ƒ lastIndexOf()length: 0map: ƒ map()pop: ƒ pop()push: ƒ push()reduce: ƒ reduce()reduceRight: ƒ reduceRight()reverse: ƒ reverse()shift: ƒ shift()slice: ƒ slice()some: ƒ some()sort: ƒ sort()splice: ƒ splice()toLocaleString: ƒ toLocaleString()toString: ƒ toString()unshift: ƒ unshift()values: ƒ values()Symbol(Symbol.iterator): ƒ values()Symbol(Symbol.unscopables): {at: true, copyWithin: true, entries: true, fill: true, find: true, …}[[Prototype]]: Object class="fa-xl text-white" aria-hidden="true" >
at <Index onVnodeUnmounted=fn<onVnodeUnmounted> ref=Ref< undefined > >
at <Anonymous key="/" routeProps= Object pageKey="/" >
at <BaseTransition mode="out-in" appear=false persisted=false ... >
at <Transition name="page" mode="out-in" >
at <RouterView name=undefined route=undefined >
at <NuxtPage>
at <App key=1 >
at <NuxtRoot>
(anonymous) @ instrument.ts:123
Expected behavior Using the component should not cause a node mismatch.
Desktop (please complete the following information):
- Browser Chrome
- Version 104.0.5112.102
Additional context
Wrapping the <font-awesome-icon>
component with <client-only>
temporary fixes this issue.
Package.json
"@fortawesome/fontawesome-svg-core": "^6.1.2",
"@fortawesome/free-brands-svg-icons": "^6.1.2",
"@fortawesome/pro-light-svg-icons": "^6.1.2",
"@fortawesome/pro-regular-svg-icons": "^6.1.2",
"@fortawesome/pro-solid-svg-icons": "^6.1.2",
"@fortawesome/pro-thin-svg-icons": "^6.1.2",
"@fortawesome/vue-fontawesome": "^3.0.1",
"nuxt": "^3.0.0-rc.8",
"vue": "^3.2.37",
same here [email protected] @fortawesome/[email protected]
Also getting this issue!
We'll take a look when we get a chance.
As a workaround, you can force a icons to render client side only by wrapping it in another component. When this issue is fixed, you can just remove the <ClientOnly>
wrapper:
<ClientOnly>
<FaIcon v-bind="$attrs" />
</ClientOnly>
I second this: issue persists on the following package configuration:
[email protected]
@fortawesome/[email protected]
I found this comment: https://github.com/nuxt/nuxt/discussions/16014#discussioncomment-2477885 Fixed the issue for me 👍
For me the hydration warnings was solved by an fix for an other problem i had: https://github.com/FortAwesome/vue-fontawesome/issues/447#issuecomment-1476257130
I can confirm this is still an issue with the latest version of nuxt and fontawesome pro
The links above should fix the issue so let's have it clear here (instead of visiting another link):
// nuxt.config.ts
build: {
transpile: [
'@fortawesome/fontawesome-svg-core',
'@fortawesome/pro-solid-svg-
'@fortawesome/pro-regular-svg-icons',
'@fortawesome/pro-light-svg-icons',
'@fortawesome/free-brands-svg-icons'
]
}
However, I believe this is something doable with nuxt hooks in a nuxt-plugin. I started working on a nuxt module for vue-fontawesome
and hoped to do something slightly better but the current plugin is actually good enough and mine didn't bring a lot more features / easiness so I dropped it.
This should just be documented on the installation with Nuxt section of FontAwesome.
build: { transpile: [ '@fortawesome/fontawesome-svg-core', '@fortawesome/pro-solid-svg- '@fortawesome/pro-regular-svg-icons', '@fortawesome/pro-light-svg-icons', '@fortawesome/free-brands-svg-icons' ] }
The transpile should include "@fortawesome/vue-fontawesome" too. At least on my side
This is my nuxt.config.ts:
build: { transpile: [ "@fortawesome/fontawesome-svg-core", "@fortawesome/pro-solid-svg-icons", "@fortawesome/pro-regular-svg-icons", "@fortawesome/pro-light-svg-icons", "@fortawesome/vue-fontawesome", ], }, css: [ "~/assets/styles/main.scss", "@fortawesome/fontawesome-svg-core/styles.css", ],
and the error is still there:
[Vue warn]: Hydration node mismatch:
- Client vnode: svg
- Server rendered DOM: "Some text" (text) at <FontAwesomeIcon icon="fa-solid fa-spinner" >
build: { transpile: [ '@fortawesome/fontawesome-svg-core', '@fortawesome/pro-solid-svg- '@fortawesome/pro-regular-svg-icons', '@fortawesome/pro-light-svg-icons', '@fortawesome/free-brands-svg-icons' ] }
The transpile should include "@fortawesome/vue-fontawesome" too. At least on my side
this fix my issue
nuxt: 3.8.1
still issue for laravel 10 with vite (inertiajs - vue3 - ssr)
If you're curious, like I was, about why we need to transpile @fortawesome/vue-fontawesome in order to avoid this SSR hydration mismatch, it's because the module field in the package.json file from @fortawesome/vue-fontawesome specifies index.es.js as the entry point (link) but package.json doesn't specify "type": "module"
so Node treats this file as a CommonJS module. But index.es.js actually uses ESM syntax, so Node fails to load it and thus the <FontAwesomeIcon>
component fails to render on the server since it's not defined.
The Nuxt documentation does an excellent job documenting this problem:
https://nuxt.com/docs/guide/concepts/esm#what-kinds-of-problems-can-there-be
So until @fortawesome/vue-fontawesome is updated to correct this issue, simply configure Nuxt to transpile @fortawesome/vue-fontawesome:
build: {
transpile: [
'@fortawesome/vue-fontawesome',
],
},