From b1b9e0bcbc2eb328452c164af4777c860095a6d4 Mon Sep 17 00:00:00 2001 From: Andrey Shertsinger Date: Thu, 20 Dec 2018 22:50:22 +0700 Subject: [PATCH] feat(vue-app): support named views (#4410) * support named views for extendRoutes config * fix lint errors * fix lint errors 2 * some refactoring * var rename * fixture & unit tests * fix: style * nuxt-child named view example and test * nuxt element with named view in layout * lint --- examples/named-views/components/childLeft.vue | 15 ++++ examples/named-views/components/mainTop.vue | 19 +++++ examples/named-views/layouts/default.vue | 6 ++ examples/named-views/nuxt.config.js | 30 ++++++++ examples/named-views/package.json | 11 +++ examples/named-views/pages/index.vue | 73 +++++++++++++++++++ .../pages/index/child/_id/index.vue | 24 ++++++ examples/named-views/pages/index/section.vue | 16 ++++ examples/named-views/pages/main.vue | 50 +++++++++++++ packages/vue-app/template/components/nuxt.js | 6 +- packages/vue-app/template/router.js | 40 +++++++++- .../named-views/components/childLeft.vue | 13 ++++ .../named-views/components/mainTop.vue | 13 ++++ test/fixtures/named-views/layouts/default.vue | 6 ++ test/fixtures/named-views/named-views.test.js | 3 + test/fixtures/named-views/nuxt.config.js | 30 ++++++++ test/fixtures/named-views/pages/index.vue | 16 ++++ .../pages/index/child/_id/index.vue | 21 ++++++ .../named-views/pages/index/section.vue | 13 ++++ test/fixtures/named-views/pages/main.vue | 16 ++++ test/unit/named-views.test.js | 41 +++++++++++ 21 files changed, 458 insertions(+), 4 deletions(-) create mode 100644 examples/named-views/components/childLeft.vue create mode 100644 examples/named-views/components/mainTop.vue create mode 100644 examples/named-views/layouts/default.vue create mode 100644 examples/named-views/nuxt.config.js create mode 100644 examples/named-views/package.json create mode 100755 examples/named-views/pages/index.vue create mode 100644 examples/named-views/pages/index/child/_id/index.vue create mode 100644 examples/named-views/pages/index/section.vue create mode 100755 examples/named-views/pages/main.vue create mode 100644 test/fixtures/named-views/components/childLeft.vue create mode 100644 test/fixtures/named-views/components/mainTop.vue create mode 100644 test/fixtures/named-views/layouts/default.vue create mode 100644 test/fixtures/named-views/named-views.test.js create mode 100644 test/fixtures/named-views/nuxt.config.js create mode 100755 test/fixtures/named-views/pages/index.vue create mode 100644 test/fixtures/named-views/pages/index/child/_id/index.vue create mode 100644 test/fixtures/named-views/pages/index/section.vue create mode 100755 test/fixtures/named-views/pages/main.vue create mode 100644 test/unit/named-views.test.js diff --git a/examples/named-views/components/childLeft.vue b/examples/named-views/components/childLeft.vue new file mode 100644 index 0000000000..cf1a6a2d49 --- /dev/null +++ b/examples/named-views/components/childLeft.vue @@ -0,0 +1,15 @@ + + + + + diff --git a/examples/named-views/components/mainTop.vue b/examples/named-views/components/mainTop.vue new file mode 100644 index 0000000000..44b442afb0 --- /dev/null +++ b/examples/named-views/components/mainTop.vue @@ -0,0 +1,19 @@ + + + + + diff --git a/examples/named-views/layouts/default.vue b/examples/named-views/layouts/default.vue new file mode 100644 index 0000000000..20818174fc --- /dev/null +++ b/examples/named-views/layouts/default.vue @@ -0,0 +1,6 @@ + diff --git a/examples/named-views/nuxt.config.js b/examples/named-views/nuxt.config.js new file mode 100644 index 0000000000..a23f24aae9 --- /dev/null +++ b/examples/named-views/nuxt.config.js @@ -0,0 +1,30 @@ +export default { + router: { + extendRoutes(routes, resolve) { + const indexIndex = routes.findIndex(route => route.name === 'index') + let index = routes[indexIndex].children.findIndex(route => route.name === 'index-child-id') + routes[indexIndex].children[index] = { + ...routes[indexIndex].children[index], + components: { + default: routes[indexIndex].children[index].component, + left: resolve(__dirname, 'components/childLeft.vue') + }, + chunkNames: { + left: 'components/childLeft' + } + } + + index = routes.findIndex(route => route.name === 'main') + routes[index] = { + ...routes[index], + components: { + default: routes[index].component, + top: resolve(__dirname, 'components/mainTop.vue') + }, + chunkNames: { + top: 'components/mainTop' + } + } + } + } +} diff --git a/examples/named-views/package.json b/examples/named-views/package.json new file mode 100644 index 0000000000..844b5435f1 --- /dev/null +++ b/examples/named-views/package.json @@ -0,0 +1,11 @@ +{ + "name": "my-app", + "dependencies": { + "nuxt": "latest" + }, + "scripts": { + "dev": "nuxt", + "build": "nuxt build", + "start": "nuxt start" + } +} diff --git a/examples/named-views/pages/index.vue b/examples/named-views/pages/index.vue new file mode 100755 index 0000000000..37f9753ee8 --- /dev/null +++ b/examples/named-views/pages/index.vue @@ -0,0 +1,73 @@ + + + + + diff --git a/examples/named-views/pages/index/child/_id/index.vue b/examples/named-views/pages/index/child/_id/index.vue new file mode 100644 index 0000000000..85ee3b0fa1 --- /dev/null +++ b/examples/named-views/pages/index/child/_id/index.vue @@ -0,0 +1,24 @@ + + + + + diff --git a/examples/named-views/pages/index/section.vue b/examples/named-views/pages/index/section.vue new file mode 100644 index 0000000000..48834ac561 --- /dev/null +++ b/examples/named-views/pages/index/section.vue @@ -0,0 +1,16 @@ + + + + + diff --git a/examples/named-views/pages/main.vue b/examples/named-views/pages/main.vue new file mode 100755 index 0000000000..14ca7e8693 --- /dev/null +++ b/examples/named-views/pages/main.vue @@ -0,0 +1,50 @@ + + + + + diff --git a/packages/vue-app/template/components/nuxt.js b/packages/vue-app/template/components/nuxt.js index fa959832ed..fa623804bc 100644 --- a/packages/vue-app/template/components/nuxt.js +++ b/packages/vue-app/template/components/nuxt.js @@ -17,7 +17,11 @@ export default { name: 'Nuxt', props: { nuxtChildKey: String, - keepAlive: Boolean + keepAlive: Boolean, + name: { + type: String, + default: 'default' + } }, render(h) { // If there is some error diff --git a/packages/vue-app/template/router.js b/packages/vue-app/template/router.js index 9bdb17f2a9..731bd6b7e2 100644 --- a/packages/vue-app/template/router.js +++ b/packages/vue-app/template/router.js @@ -3,16 +3,50 @@ import Router from 'vue-router' import { interopDefault } from './utils' <% function recursiveRoutes(routes, tab, components, indentCount) { - let res = '' + let res = '', resMap = '' const baseIndent = tab.repeat(indentCount) const firstIndent = '\n' + tab.repeat(indentCount + 1) const nextIndent = ',' + firstIndent routes.forEach((route, i) => { - route._name = '_' + hash(route.component) - components.push({ _name: route._name, component: route.component, name: route.name, chunkName: route.chunkName }) + // If need to handle named views + if (route.components) { + let _name = '_' + hash(route.components.default) + if (splitChunks.pages) { + resMap += `${firstIndent}${tab}default: ${_name}` + } else { + resMap += `${firstIndent}${tab}default: () => ${_name}.default || ${_name}` + } + for (const k in route.components) { + _name = '_' + hash(route.components[k]) + const component = { _name, component: route.components[k] } + if (k === 'default') { + components.push({ + ...component, + name: route.name, + chunkName: route.chunkName + }) + } else { + components.push({ + ...component, + name: `${route.name}-${k}`, + chunkName: route.chunkNames[k] + }) + if (splitChunks.pages) { + resMap += `${nextIndent}${tab}${k}: ${_name}` + } else { + resMap += `${nextIndent}${tab}${k}: () => ${_name}.default || ${_name}` + } + } + } + route.component = false + } else { + route._name = '_' + hash(route.component) + components.push({ _name: route._name, component: route.component, name: route.name, chunkName: route.chunkName }) + } // @see: https://router.vuejs.org/api/#router-construction-options res += '{' res += firstIndent + 'path: ' + JSON.stringify(route.path) + res += (route.components) ? nextIndent + 'components: {' + resMap + '\n' + baseIndent + tab + '}' : '' res += (route.component) ? nextIndent + 'component: ' + (splitChunks.pages ? route._name : `() => ${route._name}.default || ${route._name}`) : '' res += (route.redirect) ? nextIndent + 'redirect: ' + JSON.stringify(route.redirect) : '' res += (route.meta) ? nextIndent + 'meta: ' + JSON.stringify(route.meta) : '' diff --git a/test/fixtures/named-views/components/childLeft.vue b/test/fixtures/named-views/components/childLeft.vue new file mode 100644 index 0000000000..14f275498d --- /dev/null +++ b/test/fixtures/named-views/components/childLeft.vue @@ -0,0 +1,13 @@ + + + + + diff --git a/test/fixtures/named-views/components/mainTop.vue b/test/fixtures/named-views/components/mainTop.vue new file mode 100644 index 0000000000..bb8a21ef07 --- /dev/null +++ b/test/fixtures/named-views/components/mainTop.vue @@ -0,0 +1,13 @@ + + + + + diff --git a/test/fixtures/named-views/layouts/default.vue b/test/fixtures/named-views/layouts/default.vue new file mode 100644 index 0000000000..9c37997d66 --- /dev/null +++ b/test/fixtures/named-views/layouts/default.vue @@ -0,0 +1,6 @@ + diff --git a/test/fixtures/named-views/named-views.test.js b/test/fixtures/named-views/named-views.test.js new file mode 100644 index 0000000000..a6f63f1ba0 --- /dev/null +++ b/test/fixtures/named-views/named-views.test.js @@ -0,0 +1,3 @@ +import { buildFixture } from '../../utils/build' + +buildFixture('named-views') diff --git a/test/fixtures/named-views/nuxt.config.js b/test/fixtures/named-views/nuxt.config.js new file mode 100644 index 0000000000..a23f24aae9 --- /dev/null +++ b/test/fixtures/named-views/nuxt.config.js @@ -0,0 +1,30 @@ +export default { + router: { + extendRoutes(routes, resolve) { + const indexIndex = routes.findIndex(route => route.name === 'index') + let index = routes[indexIndex].children.findIndex(route => route.name === 'index-child-id') + routes[indexIndex].children[index] = { + ...routes[indexIndex].children[index], + components: { + default: routes[indexIndex].children[index].component, + left: resolve(__dirname, 'components/childLeft.vue') + }, + chunkNames: { + left: 'components/childLeft' + } + } + + index = routes.findIndex(route => route.name === 'main') + routes[index] = { + ...routes[index], + components: { + default: routes[index].component, + top: resolve(__dirname, 'components/mainTop.vue') + }, + chunkNames: { + top: 'components/mainTop' + } + } + } + } +} diff --git a/test/fixtures/named-views/pages/index.vue b/test/fixtures/named-views/pages/index.vue new file mode 100755 index 0000000000..f6884f1314 --- /dev/null +++ b/test/fixtures/named-views/pages/index.vue @@ -0,0 +1,16 @@ + + + + + diff --git a/test/fixtures/named-views/pages/index/child/_id/index.vue b/test/fixtures/named-views/pages/index/child/_id/index.vue new file mode 100644 index 0000000000..cc8ea37ad3 --- /dev/null +++ b/test/fixtures/named-views/pages/index/child/_id/index.vue @@ -0,0 +1,21 @@ + + + + + diff --git a/test/fixtures/named-views/pages/index/section.vue b/test/fixtures/named-views/pages/index/section.vue new file mode 100644 index 0000000000..ae9b046728 --- /dev/null +++ b/test/fixtures/named-views/pages/index/section.vue @@ -0,0 +1,13 @@ + + + + + diff --git a/test/fixtures/named-views/pages/main.vue b/test/fixtures/named-views/pages/main.vue new file mode 100755 index 0000000000..1c9634da85 --- /dev/null +++ b/test/fixtures/named-views/pages/main.vue @@ -0,0 +1,16 @@ + + + + + diff --git a/test/unit/named-views.test.js b/test/unit/named-views.test.js new file mode 100644 index 0000000000..ca47db8c59 --- /dev/null +++ b/test/unit/named-views.test.js @@ -0,0 +1,41 @@ +import { getPort, loadFixture, Nuxt } from '../utils' + +let port +let nuxt = null + +describe('named views', () => { + beforeAll(async () => { + const options = await loadFixture('named-views') + nuxt = new Nuxt(options) + port = await getPort() + await nuxt.server.listen(port, '0.0.0.0') + }) + + test('/ - no child, no named', async () => { + const { html } = await nuxt.server.renderRoute('/') + expect(html).toContain('LEFT::LEFT') + expect(html).toContain('CHILD::CHILD') + expect(html).toContain('TOP::TOP') + }) + + test('/section - have child, no named', async () => { + const { html } = await nuxt.server.renderRoute('/section') + expect(html).toContain('LEFT::LEFT') + expect(html).toMatch(new RegExp('CHILD:This page does not have left panel.:CHILD')) + expect(html).toContain('TOP::TOP') + }) + + test('/child/123 - have child, have named', async () => { + const { html } = await nuxt.server.renderRoute('/child/123') + expect(html).toMatch(new RegExp('LEFT:Child Left content!:LEFT')) + expect(html).toMatch(new RegExp('CHILD:Child content ID:123!:CHILD')) + expect(html).toContain('TOP::TOP') + }) + + test('/main - no child, no named left, have named top', async () => { + const { html } = await nuxt.server.renderRoute('/main') + expect(html).toMatch(new RegExp('TOP:Main Top content!:TOP')) + expect(html).toContain('LEFT::LEFT') + expect(html).toContain('CHILD::CHILD') + }) +})