diff --git a/packages/vue-app/template/client.js b/packages/vue-app/template/client.js index 404517bc99..23b1079eaa 100644 --- a/packages/vue-app/template/client.js +++ b/packages/vue-app/template/client.js @@ -137,20 +137,21 @@ function mapTransitions (toComponents, to, from) { } <% } %> <% if (loading) { %>async <% } %>function loadAsyncComponents (to, from, next) { - // Check if route path changed (this._pathChanged), only if the page is not an error (for validate()) - this._pathChanged = Boolean(app.nuxt.err) || from.path !== to.path - this._queryChanged = JSON.stringify(to.query) !== JSON.stringify(from.query) + // Check if route changed (this._routeChanged), only if the page is not an error (for validate()) + this._routeChanged = Boolean(app.nuxt.err) || from.name !== to.name + this._paramChanged = !this._routeChanged && from.path !== to.path + this._queryChanged = !this._paramChanged && from.fullPath !== to.fullPath this._diffQuery = (this._queryChanged ? getQueryDiff(to.query, from.query) : []) <% if (loading) { %> - if (this._pathChanged && this.$loading.start && !this.$loading.manual) { + if ((this._routeChanged || this._paramChanged) && this.$loading.start && !this.$loading.manual) { this.$loading.start() } <% } %> try { <% if (loading) { %> - if (!this._pathChanged && this._queryChanged) { + if (this._queryChanged) { const Components = await resolveRouteComponents( to, (Component, instance) => ({ Component, instance }) @@ -268,7 +269,7 @@ function callMiddleware () { } <% } %> async function render (to, from, next) { - if (this._pathChanged === false && this._queryChanged === false) { + if (this._routeChanged === false && this._paramChanged === false && this._queryChanged === false) { return next() } // Handle first render on SPA mode @@ -432,11 +433,17 @@ async function render (to, from, next) { // Check if only children route changed Component._path = compile(to.matched[matches[i]].path)(to.params) Component._dataRefresh = false - // Check if Component need to be refreshed (call asyncData & fetch) - // Only if its slug has changed or is watch query changes - if ((this._pathChanged && this._queryChanged) || Component._path !== _lastPaths[i]) { + const childPathChanged = Component._path !== _lastPaths[i] + // Refresh component (call asyncData & fetch) when: + // Route path changed part includes current component + // Or route param changed part includes current component and watchParam is not `false` + // Or route query is changed and watchQuery returns `true` + if (this._routeChanged && childPathChanged) { Component._dataRefresh = true - } else if (!this._pathChanged && this._queryChanged) { + } else if (this._paramChanged && childPathChanged) { + const watchParam = Component.options.watchParam + Component._dataRefresh = watchParam !== false + } else if (this._queryChanged) { const watchQuery = Component.options.watchQuery if (watchQuery === true) { Component._dataRefresh = true @@ -584,7 +591,7 @@ function showNextPage (to) { // When navigating on a different route but the same component is used, Vue.js // Will not update the instance data, so we have to update $data ourselves function fixPrepatch (to, ___) { - if (this._pathChanged === false && this._queryChanged === false) { + if (this._routeChanged === false && this._paramChanged === false && this._queryChanged === false) { return } diff --git a/test/dev/unicode-base.size-limit.test.js b/test/dev/unicode-base.size-limit.test.js index f15198268e..1f1f46c1fe 100644 --- a/test/dev/unicode-base.size-limit.test.js +++ b/test/dev/unicode-base.size-limit.test.js @@ -20,7 +20,6 @@ describe('nuxt minimal vue-app bundle size limit', () => { it('should stay within the size limit range', async () => { const filter = filename => filename === 'vue-app.nuxt.js' const legacyResourcesSize = await getResourcesSize(distDir, 'client', { filter }) - const LEGACY_JS_RESOURCES_KB_SIZE = 15.7 expect(legacyResourcesSize.uncompressed).toBeWithinSize(LEGACY_JS_RESOURCES_KB_SIZE) }) diff --git a/test/e2e/children.patch.browser.test.js b/test/e2e/children.patch.browser.test.js index c21be63a1b..9c3bd69b83 100644 --- a/test/e2e/children.patch.browser.test.js +++ b/test/e2e/children.patch.browser.test.js @@ -27,7 +27,7 @@ describe('children patch (browser)', () => { }) }) - test('Loading /patch and keep ', async () => { + test('Loading /patch and keep', async () => { page = await browser.page(url('/patch')) const h1 = await page.$text('h1') @@ -37,86 +37,119 @@ describe('children patch (browser)', () => { dates.patch = await page.$text('[data-date-patch]') }) - test('Navigate to /patch/1', async () => { - const { hook } = await page.nuxt.navigate('/patch/1', false) - await hook + describe('refresh child component if param changed', () => { + test('Navigate to /patch/1', async () => { + const { hook } = await page.nuxt.navigate('/patch/1', false) + await hook - const h2 = await page.$text('h2') - expect(h2.includes('_id:')).toBe(true) - dates.id = await page.$text('[data-date-id]') + const h2 = await page.$text('h2') + expect(h2.includes('_id:')).toBe(true) + dates.id = await page.$text('[data-date-id]') - expect(dates.patch).toBe(await page.$text('[data-date-patch]')) + expect(dates.patch).toBe(await page.$text('[data-date-patch]')) + }) + + test('Navigate to /patch/2', async () => { + await page.nuxt.navigate('/patch/2') + const date = await page.$text('[data-date-id]') + + expect(await page.$text('h3')).toBe('Index') + expect(dates.patch).toBe(await page.$text('[data-date-patch]')) + expect(+dates.id < +date).toBe(true) + dates.id = date + }) }) - test('Navigate to /patch/2', async () => { - await page.nuxt.navigate('/patch/2') - const date = await page.$text('[data-date-id]') + describe('resue component if only query is changed', () => { + test('Navigate to /patch/2?test=true', async () => { + await page.nuxt.navigate('/patch/2?test=true') + expect(dates.patch).toBe(await page.$text('[data-date-patch]')) + expect(dates.id).toBe(await page.$text('[data-date-id]')) + }) - expect(await page.$text('h3')).toBe('Index') - expect(dates.patch).toBe(await page.$text('[data-date-patch]')) - expect(+dates.id < +date).toBe(true) - dates.id = date + test('Navigate to /patch/2#test', async () => { + await page.nuxt.navigate('/patch/2#test') + expect(dates.patch).toBe(await page.$text('[data-date-patch]')) + expect(dates.id).toBe(await page.$text('[data-date-id]')) + }) }) - test('Navigate to /patch/2?test=true', async () => { - await page.nuxt.navigate('/patch/2?test=true') - expect(dates.patch).toBe(await page.$text('[data-date-patch]')) - expect(dates.id).toBe(await page.$text('[data-date-id]')) + describe('refresh child component if param is changed', () => { + test('Navigate to /patch/2/child', async () => { + await page.nuxt.navigate('/patch/2/child') + dates.child = await page.$text('[data-date-child]') + dates.slug = await page.$text('[data-date-child-slug]') + + expect(dates.patch).toBe(await page.$text('[data-date-patch]')) + expect(dates.id).toBe(await page.$text('[data-date-id]')) + expect(+dates.child > +dates.id).toBe(true) + expect(+dates.slug > +dates.child).toBe(true) + }) + + test('Navigate to /patch/2/child/1', async () => { + await page.nuxt.navigate('/patch/2/child/1') + const date = await page.$text('[data-date-child-slug]') + + expect(dates.patch).toBe(await page.$text('[data-date-patch]')) + expect(dates.id).toBe(await page.$text('[data-date-id]')) + expect(dates.child).toBe(await page.$text('[data-date-child]')) + expect(+date > +dates.slug).toBe(true) + dates.slug = date + }) + + test('Navigate to /patch/2/child/1?foo=bar', async () => { + await page.nuxt.navigate('/patch/2/child/1?foo=bar') + + expect(dates.patch).toBe(await page.$text('[data-date-patch]')) + expect(dates.id).toBe(await page.$text('[data-date-id]')) + expect(dates.child).toBe(await page.$text('[data-date-child]')) + expect(dates.slug).toBe(await page.$text('[data-date-child-slug]')) + }) + + test('Search a country', async () => { + const countries = await page.$$text('[data-test-search-result]') + expect(countries.length).toBe(5) + + await page.type('[data-test-search-input]', 'gu') + + await waitFor(250) + const newCountries = await page.$$text('[data-test-search-result]', true) + expect(newCountries.length).toBe(1) + expect(newCountries).toEqual(['Guinea']) + expect(await page.nuxt.routeData()).toEqual({ + path: '/patch/2/child/1', + query: { + foo: 'bar', + q: 'gu' + } + }) + }) }) - test('Navigate to /patch/2#test', async () => { - await page.nuxt.navigate('/patch/2#test') - expect(dates.patch).toBe(await page.$text('[data-date-patch]')) - expect(dates.id).toBe(await page.$text('[data-date-id]')) - }) + describe('reuse child component if param is changed but watchParam is false', () => { + test('Navigate to /patch/2/reuse', async () => { + await page.nuxt.navigate('/patch/2/reuse') + dates.slug = await page.$text('[data-date-slug]') - test('Navigate to /patch/2/child', async () => { - await page.nuxt.navigate('/patch/2/child') - dates.child = await page.$text('[data-date-child]') - dates.slug = await page.$text('[data-date-child-slug]') + expect(dates.patch).toBe(await page.$text('[data-date-patch]')) + expect(dates.id).toBe(await page.$text('[data-date-id]')) + expect(+dates.child > +dates.id).toBe(true) + }) - expect(dates.patch).toBe(await page.$text('[data-date-patch]')) - expect(dates.id).toBe(await page.$text('[data-date-id]')) - expect(+dates.child > +dates.id).toBe(true) - expect(+dates.slug > +dates.child).toBe(true) - }) + test('Navigate to /patch/2/reuse/1', async () => { + await page.nuxt.navigate('/patch/2/reuse/1') - test('Navigate to /patch/2/child/1', async () => { - await page.nuxt.navigate('/patch/2/child/1') - const date = await page.$text('[data-date-child-slug]') + expect(dates.patch).toBe(await page.$text('[data-date-patch]')) + expect(dates.id).toBe(await page.$text('[data-date-id]')) + expect(dates.slug).toBe(await page.$text('[data-date-slug]')) + }) - expect(dates.patch).toBe(await page.$text('[data-date-patch]')) - expect(dates.id).toBe(await page.$text('[data-date-id]')) - expect(dates.child).toBe(await page.$text('[data-date-child]')) - expect(+date > +dates.slug).toBe(true) - dates.slug = date - }) + test('Navigate to /patch/2/reuse/2', async () => { + await page.nuxt.navigate('/patch/2/reuse/2') - test('Navigate to /patch/2/child/1?foo=bar', async () => { - await page.nuxt.navigate('/patch/2/child/1?foo=bar') - - expect(dates.patch).toBe(await page.$text('[data-date-patch]')) - expect(dates.id).toBe(await page.$text('[data-date-id]')) - expect(dates.child).toBe(await page.$text('[data-date-child]')) - expect(dates.slug).toBe(await page.$text('[data-date-child-slug]')) - }) - - test('Search a country', async () => { - const countries = await page.$$text('[data-test-search-result]') - expect(countries.length).toBe(5) - - await page.type('[data-test-search-input]', 'gu') - - await waitFor(250) - const newCountries = await page.$$text('[data-test-search-result]', true) - expect(newCountries.length).toBe(1) - expect(newCountries).toEqual(['Guinea']) - expect(await page.nuxt.routeData()).toEqual({ - path: '/patch/2/child/1', - query: { - foo: 'bar', - q: 'gu' - } + expect(dates.patch).toBe(await page.$text('[data-date-patch]')) + expect(dates.id).toBe(await page.$text('[data-date-id]')) + expect(dates.slug).toBe(await page.$text('[data-date-slug]')) }) }) diff --git a/test/fixtures/children/layouts/patch.vue b/test/fixtures/children/layouts/patch.vue index 1b5cdc7520..ae84f457b5 100644 --- a/test/fixtures/children/layouts/patch.vue +++ b/test/fixtures/children/layouts/patch.vue @@ -42,6 +42,21 @@ /patch/2/child/1?query=true#test +