3.9.0 is the next minor release.
👀 Highlights
A very merry Christmas to you and yours from all Nuxters involved in this release! 🎁🎄
We have lots of features packed into v3.9.0 and can't wait for you to try them out.
⚡️ Vite 5
This release comes with Vite 5 and Rollup 4 support. Module authors may need to check to ensure that any vite plugins you're creating are compatible with these latest releases.
This comes with a whole host of great improvements and bug fixes - check out the Vite changelog for more info.
✨ Vue 3.4 ready
This release is tested with the latest Vue 3.4 release candidate, and has the necessary configuration to take advantage of new features in Vue 3.4, including debugging hydration errors in production (just set debug: true) in your Nuxt config.
👉 To take advantage, just update your vue version once v3.4 is released, or try out the release candidate today:
{
"dependencies": {
"nuxt": "3.9.0",
"vue": "3.4.0-rc.1",
"vue-router": "latest"
}
}🏝️ Interactive Server Components
This is a highly-experimental update, but it's now possible to play around with interactive components within Nuxt server components. You'll need to enable this new feature additionally to component islands:
export default defineNuxtConfig({
experimental: {
componentIslands: {
selectiveClient: true
}
}
})Now, within a server component, you can specify components to hydrate by using the nuxt-client directive:
<NuxtLink :to="/" nuxt-client />We're pretty excited about this one - so do let us know how you're using it! 🙏
🔥 Automatic Server Optimisations
We now use Vite's new AST-aware 'define' to perform more accurate replacements on server-side code, meaning code like this will no longer throw an error:
<script setup lang="ts">
if (document) {
console.log(document.querySelector('div'))
}
</script>This hasn't been possible until now because we haven't wanted to run the risk of accidentally replacing normal words like document within non-JS parts of your apps. But Vite's new define functionality is powered by esbuild and is syntax-aware, so we feel confident in enabling this functionality. Nevertheless, you can opt out if you need to:
export default defineNuxtConfig({
hooks: {
'vite:extendConfig' (config) {
delete config.define!.document
}
}
})🚦 Granular Loading API
We now have a new hook-based system for <NuxtLoadingIndicator>, including a useLoadingIndicator composable that lets you control/stop/start the loading state. You can also hook into page:loading:start and page:loading:end if you prefer.
You can read more in the docs and in the original PR (#24010).
🏁 Run single events in callOnce
Sometimes you only want to run code once, no matter how many times you load a page - and you don't want to run it again on the client if it ran on the server.
For this, we have a new utility: callOnce (#24787).
<script setup>
const websiteConfig = useState('config')
await callOnce(async () => {
console.log('This will only be logged once')
websiteConfig.value = await $fetch('https://my-cms.com/api/website-config')
})
</script>Note that this utility is context-aware so it must be called in component setup function or Nuxt plugin, as with other Nuxt composables.
🚨 Error Types
For a while now, errors returned by useAsyncData and useFetch have been typed pretty generically as Error. We've significantly improved the type possibilities for them to make them more accurate in terms of what you'll actually receive. (We normalise errors with the h3 createError utility under the hood, so they can be serialised from server to client, for example.)
We've tried to implement the type change in a backwards compatible way, but you might notice that you need to update the generic if you're manually configuring the generics for these composables. See (#24396) for more information, and do let us know if you experience any issues.
🔥 Schema Performance
We've taken some time in this release to make some minor performance improvements, so you should notice some things are a bit faster. This is an ongoing project and we have ideas for improving initial load time of the Nuxt dev server.
✅ Upgrading
As usual, our recommendation for upgrading is to run:
nuxi upgrade --forceThis will refresh your lockfile as well, and ensures that you pull in updates from other dependencies that Nuxt relies on, particularly in the unjs ecosystem.
👉 Changelog
🚀 Enhancements
- nuxt: Warn when page uses a layout without
<NuxtLayout>(#24116) - kit: Support prepend option for
addComponentsDir(#24309) - kit: Allow customising logger options (#24243)
- nuxt: Allow readonly option for
useCookie(#24503) - nuxt: Add path to
error.datawhen throwing 404 errors (#24674) - kit: Load
/moduleor/nuxtmodule subpath if it exists (#24707) - nuxt: Layers support for spa loading template (#24709)
- nuxt: Expose
refreshon islands and server components (#24261) - nuxt: Add
dedupeoption for data fetching composables (#24564) - vite: Replace browser globals with
undefinedon server (#24711) - nuxt: Allow plugins to specify dependencies (#24127)
- kit: Add new
addServerScanDircomposable (#24001) - nuxt: Transform
setupwithindefineComponentoptions (#24515) - nuxt: Allow customising fallback layout (#24777)
- nuxt:
useRequestHeaderutility (#24781) - nuxt: Move loading api behind hooks (#24010)
- nuxt: Add
callOnceutil to allow running code only once (#24787) - nuxt: Allow client components within
NuxtIsland(#22649) - schema: Default to
bundlermodule resolution (#22821) - kit,nuxt,vite,webpack: Add
toArrayutil (#24857)
🔥 Performance
- vite: Avoid duplicate
resolveoperation (#24736) - nuxt: Avoid duplicate iterations over layers (#24730)
- kit: Avoid duplicate
joinoperation (#24717) - vite: Simplify manifest property acccess (#24715)
- nuxt: Don't dedupe fewer than two middleware/plugins (#24718)
- schema: Avoid duplicate
getoperations (#24734) - schema: Use parallel promises (#24771)
- nuxt: Avoid duplicate
useRuntimeConfigcall (#24843) - vite: Avoid duplicate
JSON.stringifyoperation (#24848)
🩹 Fixes
- nuxt: Avoid recursive ssr errors (#24399)
- nuxt: Improve path resolve for
import.d.ts(#24413) - nuxt: Remove experimental
reactivityTransform(vue 3.4) (#24477) - nuxt: Ignore manifest when prerendering (#24504)
- nuxt: Don't strip literals from template in
<DevOnly>(#24511) - vite: Use
isBuiltinpolyfill for greater node support (#24512) - nuxt: Island components with number prefix (#24469)
- nuxt: Use consistent annotations for tree-shaking (#24514)
- nuxt: Skip prerendering all pages in hash mode (#24517)
- nuxt: Skip router middleware/redirections for islands (#24421)
- nuxt: Remove trailing slash before checking if prerendered (#24516)
- nuxt: Skip check for
<NuxtLayout>usage in islands (#24529) - vite,webpack: Don't add type checker/analyzer when testing (#24608)
- nuxt: Do not try auto-install outside of a Nuxt context (#24605)
- nuxt: Merge and apply layer hooks (#24639)
- nuxt: Only add/remove trailing slash for http protocols (#23296)
- nuxt: Ensure
errorinuseAsyncDatahas correct type (#24396) - nuxt: Add
appManifestmiddleware after modules run (#24786) - nuxt: Revert async transform of
setupwithindefineComponent(#24784) - nuxt: Eager load island components map (#24584)
- nuxt: Register override hooks separately (#24833)
- nuxt: Add
__VUE_PROD_HYDRATION_MISMATCH_DETAILS__(#24836) - kit: Auto-detect
modefromfilePathforaddComponent(#24835) - schema: Revert
bundlermodule resolution due to lack of support (22ce98d61) - kit: Don't add local
~/modulesdirs tomodulesDir(#24457)
💅 Refactors
- nuxt: Use
defineComponentto infer prop types for router-link stub (dc0e8347b) - nuxt: Opt-in to future
jiti.importfor schema (#24526) - nuxt: Remove
process.*usage in nuxt vue app (#24749) - schema: Introduce
futureandfeaturesnamespace (#24880)
📖 Documentation
- Fix typo (#24395)
- Update code to show how to enable
typedPages(#24436) - Add
defineNuxtConfigto deployment example (#24451) - Update link to more info about key/keepalive (1b1cc4f4e)
- Update Nuxt 2 EOL date in roadmap (#24602)
- Prefer
~to@alias in examples (#24574) - Fix typo (6a1c05401)
- Warn about using differently names env variables (#24612)
- commands: Add tunnel option (50d46f068)
- Add file name to code block (#24620)
- Remove linking to nuxt-themes org (6f44e9470)
- Update yarn
-ooption to--open(#24644) - Add alt text for roadmap img tags (1f1049858)
- Add missing props for
<NuxtPage>(#24675) - Add more info about custom serialize/revive (#24680)
- Fix grammar (#24737)
- Add documentation on
getCachedDataoption (#24697) - Fix
addServerScanDirexample (7cd02e290) - Add panda css to styling guide (#24178)
- Highlight the possibility of middleware to return nothing (#24241)
- Setting middleware at build time (#23480)
- Remove deprecated
loadNuxtoptions (#24201) - Improvements on data-fetching (6d50b4744)
- Add documentation for
nuxi module(#24790) - Update return for
useFetchanduseAsyncData#24407 (#24775, #24407) - Add docs for runtime test environment (#24658)
- Update example test snapshots to remove escapes (5de779a7d)
- Add
addComponentsDirexample to modules author guide (#24876)
🏡 Chore
- Update variable in release scripts (258b8a706)
- Import types from '#app' (#24418)
- Update markdownlintignore (1abb5479c)
- Update vitest dependencies (#24659)
- Pin rollup to v4 (#24814)
- nuxt: Add return type for entry (#24821)
- Use
dev:prepareinstead ofbuild:stub(802b3e28c)
✅ Tests
- Re-enable accidentally disabled unit tests 🙈 (b443de230)
- Add basic benchmark tests (#24846)
- Update vitest coverage exclusions (a46b0c876)
🤖 CI
- Don't skip releases based on commit body (#24554)
- Label pull requests based on their target branch (#24468)
- Update options for GitHub app token generation (#24565)
- Notify
nuxt/bridgewhen composables change (#24752) - Don't run benchmark on main commits by default (064615e8c)
- Temporarily disable codspeed (a39d311d3)
❤️ Contributors
- Daniel Roe (@danielroe)
- Damian Głowala (@DamianGlowala)
- Isaac Qadri (@pmnzt)
- Michael Brevard (@GalacticHypernova)
- Bobbie Goede (@BobbieGoede)
- Becem (@becem-gharbi)
- Julien Huang (@huang-julien)
- Sébastien Chopin (@Atinux)
- Harlan Wilton (@harlan-zw)
- Victor Akintunde (@akintoluvic)
- Nathanaël Labreuil (@IonianPlayboy)
- Ryota Watanabe (@wattanx)
- Michael Cole (@MichaelJCole)
- Kekeocha Justin Chetachukwu (@justinkekeocha)
- Ewen Quimerc'h (@EwenQuim)
- Abraham (@anubra266)
- Luke Nelson (@luc122c)
- Eugen Guriev (@theguriev)
- Chris Bailey (@chris-bailey)
- Alper Doğan (@doganalper)
- Jamie Trip (@Jamie4224)
- Alexander Lichter (@manniL)
- Idorenyin Udoh (@idorenyinudoh)
- Phojie Rengel (@phojie)
- GJSSSS (@gjssss)
- Xxhls (@xxhls)
- Marco Solazzi (@dwightjack)
- Lehoczky Zoltán (@Lehoczky)
- RoiLeo (@roiLeo)
- Daniel Acuña (@DaniAcu)
- Sadegh Barati (@sadeghbarati)
- Anthony Fu (@antfu)
- Kostis Maninakis (@maninak)
- Pooya Parsa (@pi0)
- MaxMonteil (@MaxMonteil)