chore: clean up

This commit is contained in:
Harlan Wilton 2024-02-01 01:16:15 +11:00
parent da7a9e952e
commit 5ecde8037c
3 changed files with 187 additions and 67 deletions

View File

@ -67,7 +67,6 @@ export function defineNuxtLink (options: NuxtLinkOptions) {
}
}
// TODO migrate to TypeScript props
return defineComponent({
name: componentName,
props: {
@ -161,7 +160,9 @@ export function defineNuxtLink (options: NuxtLinkOptions) {
const prefetched = ref(false)
const el = import.meta.server ? undefined : ref<HTMLElement | null>(null)
const elRef = import.meta.server ? undefined : (ref: any) => { el!.value = props.custom ? ref?.$el?.nextElementSibling : ref?.$el }
const elRef = import.meta.server ? undefined : (ref: any) => {
el!.value = props.custom ? ref?.$el?.nextElementSibling : ref?.$el
}
const link = computed(() => {
checkPropConflicts(props, 'to', 'href')
@ -170,7 +171,7 @@ export function defineNuxtLink (options: NuxtLinkOptions) {
const href = computed(() => {
return typeof link.value === 'string' ? link.value : router.resolve(link.value).path
})
const isAbsoluteLink = computed(() => hasProtocol(href.value, { acceptRelative: true }))
const isAbsoluteLink = computed(() => hasProtocol(href.value, {acceptRelative: true}))
const as = computed(() => {
const forceAnchorTag = props.external
if (forceAnchorTag || isAbsoluteLink.value) {
@ -209,7 +210,7 @@ export function defineNuxtLink (options: NuxtLinkOptions) {
})
const anchorProps = computed(() => {
const to = link.value
const to = href.value
// Resolves `target` value
const target = props.target || null
@ -241,8 +242,10 @@ export function defineNuxtLink (options: NuxtLinkOptions) {
unobserve = null
await Promise.all([
nuxtApp.hooks.callHook('link:prefetch', href.value).catch(() => {}),
as.value === 'RouterLink' && preloadRouteComponents(link.value, router).catch(() => {})
nuxtApp.hooks.callHook('link:prefetch', href.value).catch(() => {
}),
as.value === 'RouterLink' && preloadRouteComponents(link.value, router).catch(() => {
})
])
prefetched.value = true
})
@ -251,7 +254,9 @@ export function defineNuxtLink (options: NuxtLinkOptions) {
})
})
onBeforeUnmount(() => {
if (idleId) { cancelIdleCallback(idleId) }
if (idleId) {
cancelIdleCallback(idleId)
}
unobserve?.()
unobserve = null
})
@ -261,7 +266,7 @@ export function defineNuxtLink (options: NuxtLinkOptions) {
if (import.meta.dev && import.meta.server && !props.custom) {
const isNuxtLinkChild = inject(NuxtLinkDevKeySymbol, false)
if (isNuxtLinkChild) {
console.log('[nuxt] [NuxtLink] You can\'t nest one <a> inside another <a>. This will cause a hydration error on client-side. You can pass the `custom` prop to take full control of the markup.')
console.warn('[nuxt] [NuxtLink] You can\'t nest one <a> inside another <a>. This will cause a hydration error on client-side. You can pass the `custom` prop to take full control of the markup.')
} else {
provide(NuxtLinkDevKeySymbol, true)
}
@ -277,14 +282,13 @@ export function defineNuxtLink (options: NuxtLinkOptions) {
)
}
if (typeof link.value === 'object') {
import.meta.dev && console.log('[nuxt] [NuxtLink] Providing `to` as a vue-router route is not supported with external links.', link.value)
return null
if (import.meta.dev && typeof link.value === 'object') {
console.warn('[nuxt] [NuxtLink] Providing `to` as a vue-router route is not supported with external links.', href.value)
}
const navigate = () => {
if (isAbsoluteLink.value) {
import.meta.dev && console.log('[nuxt] [NuxtLink] Navigating to an absolute link using `navigate()` isn\'t supported', anchorProps.value.href)
import.meta.dev && console.warn('[nuxt] [NuxtLink] Navigating to an absolute link using `navigate()` isn\'t supported.', href.value)
return
}
return navigateTo(anchorProps.value.href, {

View File

@ -526,55 +526,164 @@ describe('nuxt links', () => {
const data: Record<string, string[]> = {}
for (const selector of ['nuxt-link', 'router-link', 'link-with-trailing-slash', 'link-without-trailing-slash']) {
data[selector] = []
for (const match of html.matchAll(new RegExp(`href="([^"]*)"[^>]*class="[^"]*\\b${selector}\\b`, 'g'))) {
data[selector].push(match[1])
// extract all anchor tags
for (const match of html.matchAll(new RegExp(`<a[^>]+class="[^"]*${selector}[^"]*"[^>]*>`, 'g'))) {
data[selector].push(match)
}
}
expect(data).toMatchInlineSnapshot(`
{
"link-with-trailing-slash": [
"/",
"/nuxt-link/trailing-slash/",
"/nuxt-link/trailing-slash/",
"/nuxt-link/trailing-slash/?test=true&amp;thing=other/thing#thing-other",
"/nuxt-link/trailing-slash/?test=true&amp;thing=other/thing#thing-other",
"/nuxt-link/trailing-slash/",
"/nuxt-link/trailing-slash/?with-state=true",
"/nuxt-link/trailing-slash/?without-state=true",
"https://example.com/page.html",
[
"<a href="/" class="link-with-trailing-slash">",
],
[
"<a aria-current="page" href="/nuxt-link/trailing-slash/" class="foo-active-class bar-exact-active-class link-with-trailing-slash">",
],
[
"<a aria-current="page" href="/nuxt-link/trailing-slash/" class="foo-active-class bar-exact-active-class link-with-trailing-slash">",
],
[
"<a aria-current="page" href="/nuxt-link/trailing-slash/?test=true&amp;thing=other/thing#thing-other" class="foo-active-class bar-exact-active-class link-with-trailing-slash">",
],
[
"<a aria-current="page" href="/nuxt-link/trailing-slash/?test=true&amp;thing=other/thing#thing-other" class="foo-active-class bar-exact-active-class link-with-trailing-slash">",
],
[
"<a aria-current="page" href="/nuxt-link/trailing-slash/" class="foo-active-class bar-exact-active-class link-with-trailing-slash">",
],
[
"<a aria-current="page" href="/nuxt-link/trailing-slash/?with-state=true" class="foo-active-class bar-exact-active-class link-with-trailing-slash">",
],
[
"<a aria-current="page" href="/nuxt-link/trailing-slash/?without-state=true" class="foo-active-class bar-exact-active-class link-with-trailing-slash">",
],
[
"<a href="https://example.com/page.html" rel="noopener noreferrer" class="link-with-trailing-slash">",
],
[
"<a href="/nuxt-link/https://example.com/page.html" rel="noopener noreferrer" class="link-with-trailing-slash">",
],
[
"<a href="/foo" rel="noopener noreferrer" class="link-with-trailing-slash">",
],
[
"<a href="/foo" rel="noopener noreferrer" class="link-with-trailing-slash">",
],
],
"link-without-trailing-slash": [
"/",
"/nuxt-link/trailing-slash",
"/nuxt-link/trailing-slash",
"/nuxt-link/trailing-slash?test=true&amp;thing=other/thing#thing-other",
"/nuxt-link/trailing-slash?test=true&amp;thing=other/thing#thing-other",
"/nuxt-link/trailing-slash",
"/nuxt-link/trailing-slash?with-state=true",
"/nuxt-link/trailing-slash?without-state=true",
"https://example.com/page.html",
[
"<a href="/" class="link-without-trailing-slash">",
],
[
"<a aria-current="page" href="/nuxt-link/trailing-slash" class="foo-active-class bar-exact-active-class link-without-trailing-slash">",
],
[
"<a aria-current="page" href="/nuxt-link/trailing-slash" class="foo-active-class bar-exact-active-class link-without-trailing-slash">",
],
[
"<a aria-current="page" href="/nuxt-link/trailing-slash?test=true&amp;thing=other/thing#thing-other" class="foo-active-class bar-exact-active-class link-without-trailing-slash">",
],
[
"<a aria-current="page" href="/nuxt-link/trailing-slash?test=true&amp;thing=other/thing#thing-other" class="foo-active-class bar-exact-active-class link-without-trailing-slash">",
],
[
"<a aria-current="page" href="/nuxt-link/trailing-slash" class="foo-active-class bar-exact-active-class link-without-trailing-slash">",
],
[
"<a aria-current="page" href="/nuxt-link/trailing-slash?with-state=true" class="foo-active-class bar-exact-active-class link-without-trailing-slash">",
],
[
"<a aria-current="page" href="/nuxt-link/trailing-slash?without-state=true" class="foo-active-class bar-exact-active-class link-without-trailing-slash">",
],
[
"<a href="https://example.com/page.html" rel="noopener noreferrer" class="link-without-trailing-slash">",
],
[
"<a href="/nuxt-link/https://example.com/page.html" rel="noopener noreferrer" class="link-without-trailing-slash">",
],
[
"<a href="/foo" rel="noopener noreferrer" class="link-without-trailing-slash">",
],
[
"<a href="/foo" rel="noopener noreferrer" class="link-without-trailing-slash">",
],
],
"nuxt-link": [
"/",
"/nuxt-link/trailing-slash",
"/nuxt-link/trailing-slash/",
"/nuxt-link/trailing-slash?test=true&amp;thing=other/thing#thing-other",
"/nuxt-link/trailing-slash/?test=true&amp;thing=other/thing#thing-other",
"/nuxt-link/trailing-slash",
"/nuxt-link/trailing-slash?with-state=true",
"/nuxt-link/trailing-slash?without-state=true",
"https://example.com/page.html",
[
"<a href="/" class="nuxt-link">",
],
[
"<a aria-current="page" href="/nuxt-link/trailing-slash" class="foo-active-class bar-exact-active-class nuxt-link">",
],
[
"<a aria-current="page" href="/nuxt-link/trailing-slash/" class="foo-active-class bar-exact-active-class nuxt-link">",
],
[
"<a aria-current="page" href="/nuxt-link/trailing-slash?test=true&amp;thing=other/thing#thing-other" class="foo-active-class bar-exact-active-class nuxt-link">",
],
[
"<a aria-current="page" href="/nuxt-link/trailing-slash/?test=true&amp;thing=other/thing#thing-other" class="foo-active-class bar-exact-active-class nuxt-link">",
],
[
"<a aria-current="page" href="/nuxt-link/trailing-slash" class="foo-active-class bar-exact-active-class nuxt-link">",
],
[
"<a aria-current="page" href="/nuxt-link/trailing-slash?with-state=true" class="foo-active-class bar-exact-active-class nuxt-link">",
],
[
"<a aria-current="page" href="/nuxt-link/trailing-slash?without-state=true" class="foo-active-class bar-exact-active-class nuxt-link">",
],
[
"<a href="https://example.com/page.html" rel="noopener noreferrer" class="nuxt-link">",
],
[
"<a href="/nuxt-link/https://example.com/page.html" rel="noopener noreferrer" class="nuxt-link">",
],
[
"<a href="/foo" rel="noopener noreferrer" class="nuxt-link">",
],
[
"<a href="/foo" rel="noopener noreferrer" class="nuxt-link">",
],
],
"router-link": [
"/",
"/nuxt-link/trailing-slash",
"/nuxt-link/trailing-slash/",
"/nuxt-link/trailing-slash?test=true&amp;thing=other/thing#thing-other",
"/nuxt-link/trailing-slash/?test=true&amp;thing=other/thing#thing-other",
"/nuxt-link/trailing-slash",
"/nuxt-link/trailing-slash?with-state=true",
"/nuxt-link/trailing-slash?without-state=true",
"/nuxt-link/https://example.com/page.html",
[
"<a href="/" class="router-link">",
],
[
"<a aria-current="page" href="/nuxt-link/trailing-slash" class="foo-active-class bar-exact-active-class router-link">",
],
[
"<a aria-current="page" href="/nuxt-link/trailing-slash/" class="foo-active-class bar-exact-active-class router-link">",
],
[
"<a aria-current="page" href="/nuxt-link/trailing-slash?test=true&amp;thing=other/thing#thing-other" class="foo-active-class bar-exact-active-class router-link">",
],
[
"<a aria-current="page" href="/nuxt-link/trailing-slash/?test=true&amp;thing=other/thing#thing-other" class="foo-active-class bar-exact-active-class router-link">",
],
[
"<a aria-current="page" href="/nuxt-link/trailing-slash" class="foo-active-class bar-exact-active-class router-link">",
],
[
"<a aria-current="page" href="/nuxt-link/trailing-slash?with-state=true" class="foo-active-class bar-exact-active-class router-link">",
],
[
"<a aria-current="page" href="/nuxt-link/trailing-slash?without-state=true" class="foo-active-class bar-exact-active-class router-link">",
],
[
"<a href="/nuxt-link/https://example.com/page.html" class="router-link">",
],
[
"<a href="/nuxt-link/https://example.com/page.html" class="router-link" external="true">",
],
[
"<a href="/foo" class="router-link" external="true">",
],
[
"<a href="/foo" class="router-link" external="true">",
],
],
}
`)

View File

@ -6,15 +6,22 @@ const LinkWithoutTrailingSlash = defineNuxtLink({
trailingSlash: 'remove'
})
const links = [
'/',
'/nuxt-link/trailing-slash',
'/nuxt-link/trailing-slash/',
'/nuxt-link/trailing-slash?test=true&thing=other/thing#thing-other',
'/nuxt-link/trailing-slash/?test=true&thing=other/thing#thing-other',
{ name: 'nuxt-link-trailing-slash' },
{ query: { 'with-state': 'true' }, state: { foo: 'bar' } },
{ query: { 'without-state': 'true' } },
'https://example.com/page.html'
{ to: '/', },
{ to: '/nuxt-link/trailing-slash',},
{ to: '/nuxt-link/trailing-slash/',},
{ to: '/nuxt-link/trailing-slash?test=true&thing=other/thing#thing-other',},
{ to: '/nuxt-link/trailing-slash/?test=true&thing=other/thing#thing-other',},
{ to: { name: 'nuxt-link-trailing-slash' },},
{ to: { query: { 'with-state': 'true' }, state: { foo: 'bar' } },},
{ to: { query: { 'without-state': 'true' } }},
// Trailing slashes are applied to implicit external links
{ to: 'https://example.com/page.html' },
// Explicit external links do not when using vue-router object
{ to: { path: 'https://example.com/page.html' }, external: true },
// Explicit external links (that are relative) that use vue-router object adds base and trailing slash
{ to: { path: '/foo' }, external: true },
// Explicit external for relative path trailing slashes is applied
{ to: '/foo', external: true },
] as const
const route = useRoute()
@ -42,13 +49,13 @@ const windowState = computed(() => {
:key="index"
>
<LinkWithTrailingSlash
:to="link"
v-bind="link"
class="link-with-trailing-slash"
>
<LinkWithTrailingSlash
v-slot="{ href }"
custom
:to="link"
v-bind="link"
>
{{ href }}
</LinkWithTrailingSlash>
@ -63,13 +70,13 @@ const windowState = computed(() => {
:key="index"
>
<LinkWithoutTrailingSlash
:to="link"
v-bind="link"
class="link-without-trailing-slash"
>
<LinkWithoutTrailingSlash
v-slot="{ href }"
custom
:to="link"
v-bind="link"
>
{{ href }}
</LinkWithoutTrailingSlash>
@ -84,13 +91,13 @@ const windowState = computed(() => {
:key="index"
>
<NuxtLink
:to="link"
v-bind="link"
class="nuxt-link"
>
<NuxtLink
v-slot="{ href }"
custom
:to="link"
v-bind="link"
>
{{ href }}
</NuxtLink>
@ -105,13 +112,13 @@ const windowState = computed(() => {
:key="index"
>
<RouterLink
:to="link"
v-bind="link"
class="router-link"
>
<RouterLink
v-slot="{ href }"
custom
:to="link"
v-bind="link"
>
{{ href }}
</RouterLink>