mirror of
https://github.com/nuxt/nuxt.git
synced 2025-02-18 14:41:25 +00:00
feat(vue-app): add prefetch
prop to <nuxt-link>
(#6292)
This commit is contained in:
parent
ac5066c4e0
commit
7b3155347c
@ -17,7 +17,7 @@ import {
|
|||||||
globalHandleError
|
globalHandleError
|
||||||
} from './utils.js'
|
} from './utils.js'
|
||||||
import { createApp<% if (features.layouts) { %>, NuxtError<% } %> } from './index.js'
|
import { createApp<% if (features.layouts) { %>, NuxtError<% } %> } from './index.js'
|
||||||
import NuxtLink from './components/nuxt-link.<%= features.clientPrefetch && router.prefetchLinks ? "client" : "server" %>.js' // should be included after ./index.js
|
import NuxtLink from './components/nuxt-link.<%= features.clientPrefetch ? "client" : "server" %>.js' // should be included after ./index.js
|
||||||
<% if (isDev) { %>import consola from 'consola'<% } %>
|
<% if (isDev) { %>import consola from 'consola'<% } %>
|
||||||
|
|
||||||
<% if (isDev) { %>consola.wrapConsole()
|
<% if (isDev) { %>consola.wrapConsole()
|
||||||
|
@ -29,6 +29,10 @@ export default {
|
|||||||
name: 'NuxtLink',
|
name: 'NuxtLink',
|
||||||
extends: Vue.component('RouterLink'),
|
extends: Vue.component('RouterLink'),
|
||||||
props: {
|
props: {
|
||||||
|
prefetch: {
|
||||||
|
type: Boolean,
|
||||||
|
default: <%= router.prefetchLinks ? 'true' : 'false' %>
|
||||||
|
},
|
||||||
noPrefetch: {
|
noPrefetch: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false
|
default: false
|
||||||
@ -39,7 +43,7 @@ export default {
|
|||||||
}<% } %>
|
}<% } %>
|
||||||
},
|
},
|
||||||
mounted () {
|
mounted () {
|
||||||
if (!this.noPrefetch) {
|
if (this.prefetch && !this.noPrefetch) {
|
||||||
this.handleId = requestIdleCallback(this.observe, { timeout: 2e3 })
|
this.handleId = requestIdleCallback(this.observe, { timeout: 2e3 })
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -59,7 +63,7 @@ export default {
|
|||||||
}
|
}
|
||||||
// Add to observer
|
// Add to observer
|
||||||
if (this.shouldPrefetch()) {
|
if (this.shouldPrefetch()) {
|
||||||
this.$el.__prefetch = this.prefetch.bind(this)
|
this.$el.__prefetch = this.prefetchLink.bind(this)
|
||||||
observer.observe(this.$el)
|
observer.observe(this.$el)
|
||||||
this.__observed = true
|
this.__observed = true
|
||||||
}<% if (router.linkPrefetchedClass) { %> else {
|
}<% if (router.linkPrefetchedClass) { %> else {
|
||||||
@ -81,7 +85,7 @@ export default {
|
|||||||
|
|
||||||
return Components.filter(Component => typeof Component === 'function' && !Component.options && !Component.__prefetched)
|
return Components.filter(Component => typeof Component === 'function' && !Component.options && !Component.__prefetched)
|
||||||
},
|
},
|
||||||
prefetch () {
|
prefetchLink () {
|
||||||
if (!this.canPrefetch()) {
|
if (!this.canPrefetch()) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,10 @@ export default {
|
|||||||
name: 'NuxtLink',
|
name: 'NuxtLink',
|
||||||
extends: Vue.component('RouterLink'),
|
extends: Vue.component('RouterLink'),
|
||||||
props: {
|
props: {
|
||||||
|
prefetch: {
|
||||||
|
type: Boolean,
|
||||||
|
default: <%= router.prefetchLinks ? 'true' : 'false' %>
|
||||||
|
},
|
||||||
noPrefetch: {
|
noPrefetch: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false
|
default: false
|
||||||
|
@ -32,7 +32,7 @@ export async function compileTemplate (template, destination, options = {}) {
|
|||||||
if (typeof template === 'string') {
|
if (typeof template === 'string') {
|
||||||
return {
|
return {
|
||||||
src: path.resolve(rootDir, '../template', template),
|
src: path.resolve(rootDir, '../template', template),
|
||||||
dst: path.join(rootDir, '.nuxt', path.basename(template)),
|
dst: path.join(rootDir, '.nuxt', destination || path.basename(template)),
|
||||||
custom: false
|
custom: false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
163
packages/vue-app/test/nuxt-link.client.prefetch.test.js
Normal file
163
packages/vue-app/test/nuxt-link.client.prefetch.test.js
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
/**
|
||||||
|
* @jest-environment jsdom
|
||||||
|
*/
|
||||||
|
import { mount, RouterLinkStub } from '@vue/test-utils'
|
||||||
|
import { vmTick, compileTemplate, importComponent } from './__utils__'
|
||||||
|
|
||||||
|
/* eslint-disable no-console */
|
||||||
|
describe('nuxt-link prefetch', () => {
|
||||||
|
beforeAll(() => {
|
||||||
|
jest.useFakeTimers()
|
||||||
|
|
||||||
|
jest.spyOn(console, 'warn')
|
||||||
|
jest.spyOn(console, 'error')
|
||||||
|
})
|
||||||
|
|
||||||
|
afterAll(() => jest.restoreAllMocks())
|
||||||
|
|
||||||
|
test('when router.prefetchLinks is set to false, link with no prop should not be prefetched',
|
||||||
|
async () => {
|
||||||
|
const compiledTemplatePath = await compileTemplate(
|
||||||
|
'components/nuxt-link.client.js',
|
||||||
|
'nuxt-link.client.prefetch.0.js',
|
||||||
|
{ router: { prefetchLinks: false } }
|
||||||
|
)
|
||||||
|
|
||||||
|
const Component = await importComponent(compiledTemplatePath)
|
||||||
|
Component.extends = RouterLinkStub
|
||||||
|
|
||||||
|
const methods = { observe: jest.fn() }
|
||||||
|
|
||||||
|
const wrapper = mount(Component, {
|
||||||
|
propsData: { to: '/link' },
|
||||||
|
methods
|
||||||
|
})
|
||||||
|
|
||||||
|
jest.runAllTimers()
|
||||||
|
await vmTick(wrapper.vm)
|
||||||
|
|
||||||
|
expect(console.warn).not.toHaveBeenCalled()
|
||||||
|
expect(console.error).not.toHaveBeenCalled()
|
||||||
|
|
||||||
|
expect(wrapper.props('prefetch')).toBe(false)
|
||||||
|
expect(wrapper.props('noPrefetch')).toBe(false)
|
||||||
|
expect(methods.observe).not.toHaveBeenCalled()
|
||||||
|
})
|
||||||
|
|
||||||
|
test('when router.prefetchLinks is set to false, link with prefetch prop set to true should be prefetched',
|
||||||
|
async () => {
|
||||||
|
const compiledTemplatePath = await compileTemplate(
|
||||||
|
'components/nuxt-link.client.js',
|
||||||
|
'nuxt-link.client.prefetch.1.js',
|
||||||
|
{ router: { prefetchLinks: false } }
|
||||||
|
)
|
||||||
|
|
||||||
|
const Component = await importComponent(compiledTemplatePath)
|
||||||
|
Component.extends = RouterLinkStub
|
||||||
|
|
||||||
|
const methods = { observe: jest.fn() }
|
||||||
|
|
||||||
|
const wrapper = mount(Component, {
|
||||||
|
propsData: { to: '/link', prefetch: true },
|
||||||
|
methods
|
||||||
|
})
|
||||||
|
|
||||||
|
jest.runAllTimers()
|
||||||
|
await vmTick(wrapper.vm)
|
||||||
|
|
||||||
|
expect(console.warn).not.toHaveBeenCalled()
|
||||||
|
expect(console.error).not.toHaveBeenCalled()
|
||||||
|
|
||||||
|
expect(wrapper.props('prefetch')).toBe(true)
|
||||||
|
expect(wrapper.props('noPrefetch')).toBe(false)
|
||||||
|
expect(methods.observe).toHaveBeenCalled()
|
||||||
|
})
|
||||||
|
|
||||||
|
test('when router.prefetchLinks is set to true (default), link with no prop should be prefetched',
|
||||||
|
async () => {
|
||||||
|
const compiledTemplatePath = await compileTemplate(
|
||||||
|
'components/nuxt-link.client.js',
|
||||||
|
'nuxt-link.client.prefetch.2.js',
|
||||||
|
{}
|
||||||
|
)
|
||||||
|
|
||||||
|
const Component = await importComponent(compiledTemplatePath)
|
||||||
|
Component.extends = RouterLinkStub
|
||||||
|
|
||||||
|
const methods = { observe: jest.fn() }
|
||||||
|
|
||||||
|
const wrapper = mount(Component, {
|
||||||
|
propsData: { to: '/link' },
|
||||||
|
methods
|
||||||
|
})
|
||||||
|
|
||||||
|
jest.runAllTimers()
|
||||||
|
await vmTick(wrapper.vm)
|
||||||
|
|
||||||
|
expect(console.warn).not.toHaveBeenCalled()
|
||||||
|
expect(console.error).not.toHaveBeenCalled()
|
||||||
|
|
||||||
|
expect(wrapper.props('prefetch')).toBe(true)
|
||||||
|
expect(wrapper.props('noPrefetch')).toBe(false)
|
||||||
|
expect(methods.observe).toHaveBeenCalled()
|
||||||
|
})
|
||||||
|
|
||||||
|
test('when router.prefetchLinks is set to true (default), link with prefetch prop set to false should not be prefetched',
|
||||||
|
async () => {
|
||||||
|
const compiledTemplatePath = await compileTemplate(
|
||||||
|
'components/nuxt-link.client.js',
|
||||||
|
'nuxt-link.client.prefetch.3.js',
|
||||||
|
{}
|
||||||
|
)
|
||||||
|
|
||||||
|
const Component = await importComponent(compiledTemplatePath)
|
||||||
|
Component.extends = RouterLinkStub
|
||||||
|
|
||||||
|
const methods = { observe: jest.fn() }
|
||||||
|
|
||||||
|
const wrapper = mount(Component, {
|
||||||
|
propsData: { to: '/link', prefetch: false },
|
||||||
|
methods
|
||||||
|
})
|
||||||
|
|
||||||
|
jest.runAllTimers()
|
||||||
|
await vmTick(wrapper.vm)
|
||||||
|
|
||||||
|
expect(console.warn).not.toHaveBeenCalled()
|
||||||
|
expect(console.error).not.toHaveBeenCalled()
|
||||||
|
|
||||||
|
expect(wrapper.props('prefetch')).toBe(false)
|
||||||
|
expect(wrapper.props('noPrefetch')).toBe(false)
|
||||||
|
expect(methods.observe).not.toHaveBeenCalled()
|
||||||
|
})
|
||||||
|
|
||||||
|
test('when router.prefetchLinks is set to true (default), link with noPrefetch prop should not be prefetched',
|
||||||
|
async () => {
|
||||||
|
const compiledTemplatePath = await compileTemplate(
|
||||||
|
'components/nuxt-link.client.js',
|
||||||
|
'nuxt-link.client.prefetch.4.js',
|
||||||
|
{}
|
||||||
|
)
|
||||||
|
|
||||||
|
const Component = await importComponent(compiledTemplatePath)
|
||||||
|
Component.extends = RouterLinkStub
|
||||||
|
|
||||||
|
const methods = { observe: jest.fn() }
|
||||||
|
|
||||||
|
const wrapper = mount(Component, {
|
||||||
|
propsData: { to: '/link', noPrefetch: true },
|
||||||
|
methods
|
||||||
|
})
|
||||||
|
|
||||||
|
jest.runAllTimers()
|
||||||
|
await vmTick(wrapper.vm)
|
||||||
|
|
||||||
|
expect(console.warn).not.toHaveBeenCalled()
|
||||||
|
expect(console.error).not.toHaveBeenCalled()
|
||||||
|
|
||||||
|
expect(wrapper.props('prefetch')).toBe(true)
|
||||||
|
expect(wrapper.props('noPrefetch')).toBe(true)
|
||||||
|
expect(methods.observe).not.toHaveBeenCalled()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
/* eslint-enable no-console */
|
@ -5,6 +5,10 @@
|
|||||||
"to": {
|
"to": {
|
||||||
"description": "Denotes the target route of the link. When clicked, the value of the to prop will be passed to router.push() internally, so the value can be either a string or a location descriptor object."
|
"description": "Denotes the target route of the link. When clicked, the value of the to prop will be passed to router.push() internally, so the value can be either a string or a location descriptor object."
|
||||||
},
|
},
|
||||||
|
"prefetch": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "Prefetch route target (overrides router.prefetchLinks value in nuxt.config.js)."
|
||||||
|
},
|
||||||
"no-prefetch": {
|
"no-prefetch": {
|
||||||
"description": "Avoid prefetching route target."
|
"description": "Avoid prefetching route target."
|
||||||
},
|
},
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
"exact",
|
"exact",
|
||||||
"event",
|
"event",
|
||||||
"exact-active-class",
|
"exact-active-class",
|
||||||
|
"prefetch",
|
||||||
"no-prefetch"
|
"no-prefetch"
|
||||||
],
|
],
|
||||||
"description": "Component for navigating between Nuxt pages."
|
"description": "Component for navigating between Nuxt pages."
|
||||||
@ -35,6 +36,7 @@
|
|||||||
"exact",
|
"exact",
|
||||||
"event",
|
"event",
|
||||||
"exact-active-class",
|
"exact-active-class",
|
||||||
|
"prefetch",
|
||||||
"no-prefetch"
|
"no-prefetch"
|
||||||
],
|
],
|
||||||
"description": "Component for navigating between Nuxt pages."
|
"description": "Component for navigating between Nuxt pages."
|
||||||
|
Loading…
Reference in New Issue
Block a user