Skip to content

Commit c16a833

Browse files
author
Ivan Bochkarev
committed
Merge remote-tracking branch 'upstream/main'
2 parents 9739b5c + 800d08d commit c16a833

File tree

14 files changed

+1064
-909
lines changed

14 files changed

+1064
-909
lines changed

app/components/AppHeader.vue

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,17 @@ const { copy } = useClipboard()
99
const { headerLinks } = useHeaderLinks()
1010
const { version } = useDocsVersion()
1111
12+
const { tags } = useDocsTags()
13+
1214
const latestVersion = computed(() => {
1315
const versionMatch = stats.value?.version?.match(/\d+\.\d+/)
1416
return versionMatch ? versionMatch[0] : undefined
1517
})
1618
1719
const mobileDocsVersion = computed(() =>
1820
route.path.startsWith('/docs')
19-
? version.value.tag !== 'latest'
20-
? `${version.value.shortTag} (${version.value.tag})`
21+
? version.value.shortTag !== 'v4'
22+
? `${version.value.shortTag} (${tags[version.value.shortTag]})`
2123
: version.value.shortTag
2224
: undefined
2325
)

app/components/VersionSelect.vue

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<script setup lang="ts">
22
const { version, items } = useDocsVersion()
3+
const { tags } = useDocsTags()
34
</script>
45

56
<template>
@@ -24,8 +25,8 @@ const { version, items } = useDocsVersion()
2425
>
2526
<span class="truncate">{{ version.label }}</span>
2627

27-
<UBadge v-if="version.tag" :color="version.tagColor" variant="subtle" size="sm" class="rounded-full">
28-
{{ version.tag }}
28+
<UBadge v-if="tags[version.shortTag]" :color="version.tagColor" variant="subtle" size="sm" class="rounded-full">
29+
{{ tags[version.shortTag] }}
2930
</UBadge>
3031
</UButton>
3132
</template>
@@ -34,8 +35,8 @@ const { version, items } = useDocsVersion()
3435
<div class="flex items-center gap-1.5">
3536
<span class="truncate">{{ item.label }}</span>
3637

37-
<UBadge v-if="item.tag" :color="item.tagColor" variant="subtle" size="sm" class="rounded-full">
38-
{{ item.tag }}
38+
<UBadge v-if="item.shortTag" :color="item.tagColor" variant="subtle" size="sm" class="rounded-full">
39+
{{ tags[item.shortTag] }}
3940
</UBadge>
4041
</div>
4142
</template>

app/components/ads/Ads.vue

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,11 @@
11
<script setup lang="ts">
22
const { $ads } = useNuxtApp()
33
const route = useRoute()
4-
const uiPro = useState('uiProAd', () => Math.round(Math.random()))
5-
if (!useNuxtApp().isHydrating) {
6-
uiPro.value = Math.round(Math.random())
7-
}
84
</script>
95

106
<template>
117
<div class="space-y-3">
12-
<AdsUIPro v-if="uiPro" />
13-
<AdsFallback v-else-if="$ads.adBlocked.value" />
8+
<AdsFallback v-if="$ads.adBlocked.value" />
149
<LazyAdsCarbon v-else :key="route.path" />
1510
</div>
1611
</template>

app/components/module/ModuleProseImg.vue

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,3 @@
1-
<template>
2-
<NuxtImg
3-
:src="src"
4-
:alt="alt"
5-
:width="width"
6-
:height="height"
7-
/>
8-
</template>
9-
101
<script setup lang="ts">
112
import { hasProtocol, joinURL } from 'ufo'
123
@@ -37,3 +28,12 @@ const src = computed(() => {
3728
return joinURL('https://raw.githubusercontent.com/', repo, module.value.stats.defaultBranch, props.src)
3829
})
3930
</script>
31+
32+
<template>
33+
<img
34+
:src="src"
35+
:alt="alt"
36+
:width="width"
37+
:height="height"
38+
>
39+
</template>

app/composables/useDocsVersion.ts

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,16 @@ import type { BadgeProps } from '@nuxt/ui'
22

33
interface Version {
44
label: string
5-
tag: string
6-
shortTag: string
5+
shortTag: 'v4' | 'v3'
76
branch: string
87
tagColor: BadgeProps['color']
98
path: string
109
collection: 'docsv3' | 'docsv4'
1110
}
1211

13-
// TODO: get versions from npm registry
1412
const versions: Version[] = [
1513
{
1614
label: 'Version 4',
17-
tag: '4.0.1',
1815
shortTag: 'v4',
1916
branch: 'main',
2017
tagColor: 'info',
@@ -23,8 +20,6 @@ const versions: Version[] = [
2320
},
2421
{
2522
label: 'Version 3',
26-
// TODO: update this on release
27-
tag: '3.17.7',
2823
shortTag: 'v3',
2924
branch: '3.x',
3025
tagColor: 'primary',
@@ -33,6 +28,24 @@ const versions: Version[] = [
3328
}
3429
]
3530

31+
const tagMap: Record<Version['shortTag'], string> = {
32+
v3: '3x',
33+
v4: '4x'
34+
}
35+
36+
export const useDocsTags = () => {
37+
const { data: tags } = useAsyncData('versions', async () => {
38+
const { 'dist-tags': distTags } = await $fetch<{ 'dist-tags': Record<string, string> }>('https://registry.npmjs.org/nuxt')
39+
return Object.fromEntries(
40+
Object.entries(tagMap).map(([shortTag]: [keyof typeof tagMap, string]) => {
41+
return [shortTag, distTags[tagMap[shortTag]] ?? distTags.latest]
42+
})
43+
)
44+
}, { default: () => ({}) })
45+
46+
return { tags }
47+
}
48+
3649
export const useDocsVersion = () => {
3750
const route = useRoute()
3851

app/layouts/default.vue

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,19 @@ onMounted(() => {
1818
<template>
1919
<div>
2020
<UBanner
21-
id="nuxt-v4"
22-
title="Announcing Nuxt 4.0"
23-
icon="i-lucide-sparkles"
24-
to="/blog/v4"
21+
id="mastering-nuxt-v4"
22+
title="Get the official course for Nuxt 4 and save $50 with code NUXT4RDY"
23+
icon="i-lucide-book-open"
24+
to="https://masteringnuxt.com/?utm_source=nuxt&utm_medium=banner&utm_campaign=nuxt4&friend=nuxt"
25+
target="_blank"
2526
close
2627
:actions="[
2728
{
28-
label: 'Read the announcement',
29+
label: 'Claim discount',
2930
color: 'neutral',
3031
variant: 'outline',
3132
trailingIcon: 'i-lucide-arrow-right',
32-
to: '/blog/v4'
33+
to: 'https://masteringnuxt.com/?utm_source=nuxt&utm_medium=banner&utm_campaign=nuxt4&friend=nuxt'
3334
}
3435
]"
3536
/>

app/pages/modules/[slug].vue

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,13 @@
11
<script setup lang="ts">
22
import type { Module } from '~/types'
3-
import { ModuleProseA, ModuleProseKbd } from '#components'
4-
5-
const Img = (props: any) => h('img', props)
3+
import { ModuleProseA, ModuleProseKbd, ModuleProseImg } from '#components'
64
75
definePageMeta({
86
heroBackground: 'opacity-30 -z-10'
97
})
108
const route = useRoute()
119
12-
const { data: module } = await useFetch<Module>(`https://api.nuxt.com/modules/${route.params.slug}`, { key: `modules-${route.params.slug}` })
10+
const { data: module } = await useFetch<Module>(`https://api.nuxt.com/modules/${route.params.slug}`, { key: `module-${route.params.slug}` })
1311
if (!module.value) {
1412
throw createError({ statusCode: 404, statusMessage: 'Модуль не найден', fatal: true })
1513
}
@@ -168,7 +166,7 @@ defineOgImageComponent('Module', {
168166

169167
<UPage>
170168
<UPageBody>
171-
<ContentRenderer v-if="module.readme?.body" :value="module.readme" :components="{ a: ModuleProseA, img: Img, kbd: ModuleProseKbd }" />
169+
<ContentRenderer v-if="module.readme?.body" :value="module.readme" :components="{ a: ModuleProseA, img: ModuleProseImg, kbd: ModuleProseKbd }" class="first:[&_picture]:block first:[&_picture]:mb-4" />
172170
</UPageBody>
173171

174172
<template #right>

content/blog/37.v3-18.md

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
---
2+
title: Nuxt 3.18
3+
description: Nuxt 3.18 is out - bringing v4 features to v3, improved accessibility, better browser dev tooling integration, and performance enhancements!
4+
navigation: false
5+
image: /assets/blog/v3.18.png
6+
authors:
7+
- name: Daniel Roe
8+
avatar:
9+
src: https://github.com/danielroe.png
10+
to: https://bsky.app/profile/danielroe.dev
11+
date: 2025-07-28T10:00:00.000Z
12+
category: Release
13+
---
14+
15+
## 🧪 Lazy Hydration Macros
16+
17+
Building on the delayed hydration support from v3.16, we now support **lazy hydration macros** ([#31192](https://github.com/nuxt/nuxt/pull/31192))! These provide a more ergonomic way to control component hydration:
18+
19+
20+
```vue
21+
<script setup lang="ts">
22+
const LazyHydrationMyComponent = defineLazyHydrationComponent(
23+
'visible',
24+
() => import('./components/MyComponent.vue')
25+
)
26+
</script>
27+
<template>
28+
<div>
29+
<!--
30+
Hydration will be triggered when
31+
the element(s) is 100px away from entering the viewport.
32+
-->
33+
<LazyHydrationMyComponent :hydrate-on-visible="{ rootMargin: '100px' }" />
34+
</div>
35+
</template>
36+
```
37+
38+
These macros make it possible to use Nuxt's lazy hydration utilities alongside explicit component imports.
39+
40+
## ♿️ Accessibility Improvements
41+
42+
We've enhanced accessibility by including `<NuxtRouteAnnouncer>` in the built-in `app.vue` ([#32621](https://github.com/nuxt/nuxt/pull/32621)). This means page changes will be announced to screen readers, making navigation more accessible for users with visual impairments. (This only applies if you do not have an `app.vue` in your project. If you do, please keep `<NuxtRouteAnnouncer>` in your `app.vue`!)
43+
44+
## 🛠️ Enhanced Development Experience
45+
46+
### Chrome DevTools Workspace Integration
47+
48+
We've added **Chrome DevTools workspace integration** ([#32084](https://github.com/nuxt/nuxt/pull/32084)), allowing you to edit your Nuxt source files directly from Chrome DevTools. This creates a better debugging experience where changes made in DevTools are reflected in your actual source files.
49+
50+
### Better Component Type Safety
51+
52+
Component type safety has been improved with:
53+
54+
- **Typed slots for `<ClientOnly>` and `<DevOnly>`** ([#32707](https://github.com/nuxt/nuxt/pull/32707)) - better IntelliSense and error checking
55+
- **Exported `<NuxtTime>` prop types** ([#32547](https://github.com/nuxt/nuxt/pull/32547)) - easier to extend and customize
56+
57+
### New Auto-Import: `onWatcherCleanup`
58+
59+
The `onWatcherCleanup` function from `vue` is now available as an auto-import ([#32396](https://github.com/nuxt/nuxt/pull/32396)), making it easier to clean up watchers and prevent memory leaks:
60+
61+
```ts
62+
const { data } = useAsyncData('users', fetchUsers)
63+
64+
watch(data, (newData) => {
65+
const interval = setInterval(() => {
66+
// Some periodic task
67+
}, 1000)
68+
69+
// Clean up when the watcher is stopped
70+
onWatcherCleanup(() => {
71+
clearInterval(interval)
72+
})
73+
})
74+
```
75+
76+
## 📊 Observability Enhancements
77+
78+
Page routes are now **exposed to Nitro for observability** ([#32617](https://github.com/nuxt/nuxt/pull/32617)), enabling better monitoring and analytics integration with supported platforms. This allows observability tools to track page-level metrics more effectively.
79+
80+
## 🔧 Module Development Improvements
81+
82+
Module authors get several quality-of-life improvements:
83+
84+
### Simplified Server Imports
85+
86+
The `addServerImports` kit utility now **supports single imports** ([#32289](https://github.com/nuxt/nuxt/pull/32289)), making it easier to add individual server utilities:
87+
88+
```ts
89+
// Before: had to wrap in array
90+
addServerImports([{ from: 'my-package', name: 'myUtility' }])
91+
92+
// Now: can pass directly
93+
addServerImports({ from: 'my-package', name: 'myUtility' })
94+
```
95+
96+
### TypeScript Configuration
97+
98+
Modules can now **add to `typescript.hoist`** ([#32601](https://github.com/nuxt/nuxt/pull/32601)), giving them more control over TypeScript configuration and type generation.
99+
100+
## ⚡️ Performance Improvements
101+
102+
We've made several performance optimizations:
103+
104+
- **Improved Vite-node communication** via internal socket ([#32417](https://github.com/nuxt/nuxt/pull/32417)) for faster development builds
105+
- **Migration to `oxc-walker`** ([#32250](https://github.com/nuxt/nuxt/pull/32250)) and **oxc for `onPrehydrate` transforms** ([#32045](https://github.com/nuxt/nuxt/pull/32045)) for faster code transformations
106+
107+
## 🐛 Bug Fixes
108+
109+
This release also includes several important fixes:
110+
111+
- **Improved data fetching**: When computed keys change, old data is now properly retained ([#32616](https://github.com/nuxt/nuxt/pull/32616))
112+
- **Better scroll behavior**: `scrollBehaviorType` is now only used for hash scrolling ([#32622](https://github.com/nuxt/nuxt/pull/32622))
113+
- **Fixed directory aliases**: Added trailing slashes to some directory aliases for better consistency ([#32755](https://github.com/nuxt/nuxt/pull/32755))
114+
115+
## ✅ Upgrading
116+
117+
As usual, our recommendation for upgrading is to run:
118+
119+
```sh
120+
npx nuxi@latest upgrade --dedupe
121+
```
122+
123+
This refreshes your lockfile and pulls in all the latest dependencies that Nuxt relies on, especially from the unjs ecosystem.
124+
125+
## Full release notes
126+
127+
::read-more
128+
---
129+
icon: i-simple-icons-github
130+
target: _blank
131+
to: https://github.com/nuxt/nuxt/releases/tag/v3.18.0
132+
---
133+
Read the full release notes of Nuxt `v3.18.0`.
134+
::
135+
136+
A huge thank you to everyone who's been a part of this release. Over the next six months, we'll continue backporting compatible v4 features and bug fixes, so please keep the feedback coming! ❤️

content/index.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ hero:
22
title: 'The Progressive Web Framework'
33
description: Create high-quality web applications with Nuxt, the open source framework that makes full-stack development with Vue.js intuitive.
44
cta:
5-
label: Announcing Nuxt 4.0
6-
to: /blog/v4
5+
label: Nuxt v3.18 is out
6+
to: /blog/v3-18
77
icon: i-lucide-arrow-right
88
tabs:
99
- title: Minimal
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name: 'Nuxt Shadcn Dashboard'
22
slug: 'nuxt-shadcn-dashboard'
33
description: 'Shadcn Dashboard built with Nuxt'
4-
screenshotUrl: 'https://dashboard.dianprata.com/'
4+
screenshotUrl: 'https://nuxt-shadcn-dashboard.vercel.app/'
55
repo: 'dianprata/nuxt-shadcn-dashboard'
6-
demo: 'https://dashboard.dianprata.com/'
6+
demo: 'https://nuxt-shadcn-dashboard.vercel.app/'

0 commit comments

Comments
 (0)