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 @@
+
+
+ Child Left content!
+
+
+
+
+
+
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 @@
+
+
+ Main Top content!
+
+
+
+
+
+
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 @@
+
+
+
Hello there
+
This is an example of a named views
+
+ -
+
+ Root
+
+
+ -
+
+ Section
+
+
+ -
+
+ Child 123
+
+
+ -
+
+ Child 234
+
+
+ -
+
+ Main page with named view in layout
+
+
+
+
+
+
+
+
+
+
+
+
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 @@
+
+
+
Child content
+ ID:{{ id }}
+
+
+
+
+
+
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 @@
+
+
+
Section content
+
This page does not have left panel.
+
+
+
+
+
+
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 @@
+
+
+
Main page
+
This is an example of a named views
+
+ -
+
+ Root
+
+
+ -
+
+ Section
+
+
+ -
+
+ Child 123
+
+
+ -
+
+ Child 234
+
+
+ -
+
+ Main page with named view in layout
+
+
+
+
+
+
At top of this page there is named view from layout!
+
+
+
+
+
+
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 @@
+
+ Child Left content!
+
+
+
+
+
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 @@
+
+ Main Top content!
+
+
+
+
+
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 @@
+
+
+ TOP::TOP
+ PAGE::PAGE
+
+
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 @@
+
+
+ LEFT::LEFT
+ CHILD::CHILD
+
+
+
+
+
+
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 @@
+
+ Child content ID:{{ id }}!
+
+
+
+
+
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 @@
+
+ This page does not have left panel.
+
+
+
+
+
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 @@
+
+
+ LEFT::LEFT
+ CHILD::CHILD
+
+
+
+
+
+
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')
+ })
+})