From 0b8b85128fde37f9bbba3e8376b98be2dade4cb7 Mon Sep 17 00:00:00 2001 From: Alexandre Chopin Date: Sun, 11 Dec 2016 01:46:04 +0100 Subject: [PATCH] Nested dynamic routes Build and Router --- lib/app/router.js | 32 ++++++++++++++------- lib/build/index.js | 70 +++++++++++++++++++++++++++++----------------- 2 files changed, 66 insertions(+), 36 deletions(-) diff --git a/lib/app/router.js b/lib/app/router.js index 9ac3adceb2..ef8061ad85 100644 --- a/lib/app/router.js +++ b/lib/app/router.js @@ -5,8 +5,27 @@ import Router from 'vue-router' Vue.use(Router) -<% uniqBy(router.routes, '_name').forEach((route) => { %> -const <%= route._name %> = process.BROWSER_BUILD ? () => System.import('<%= route._component %>') : require('<%= route._component %>') +<% +let components = [] +function recursiveRoutes(routes, tab) { + let res = '' + routes.forEach((route, i) => { + components.push({ _name: route._name, component: route.component }) + res += tab + '{\n' + res += tab + '\tpath: ' + JSON.stringify(route.path) + ',\n' + res += tab + '\tcomponent: ' + route._name + res += (route.name) ? ',\n\t' + tab + 'name: ' + JSON.stringify(route.name) : '' + res += (route.alias) ? ',\n\t' + tab + 'alias: ' + JSON.stringify(route.alias) : '' + res += (route.redirect) ? ',\n\t' + tab + 'redirect: ' + JSON.stringify(route.redirect) : '' + res += (route.meta) ? ',\n\t' + tab + 'meta: ' + JSON.stringify(route.meta) : '' + res += (route.children) ? ',\n\t' + tab + 'children: [\n' + recursiveRoutes(routes[i].children, tab + '\t\t') + '\n\t' + tab + ']' : '' + res += '\n' + tab + '}' + (i + 1 === routes.length ? '' : ',\n') + }) + return res +} +let routes = recursiveRoutes(router.routes, '\t\t') +uniqBy(components, '_name').forEach((route) => { %> +const <%= route._name %> = process.BROWSER_BUILD ? () => System.import('<%= route.component %>') : require('<%= route.component %>') <% }) %> const scrollBehavior = (to, from, savedPosition) => { @@ -30,13 +49,6 @@ export default new Router({ linkActiveClass: '<%= router.linkActiveClass %>', scrollBehavior, routes: [ - <% router.routes.forEach((route, i) => { %> - { - path: '<%= route.path %>', - component: <%= route._name %><% if (route.name) { %>, - name: '<%= route.name %>'<% } %><% if (route.meta) { %>, - meta: <%= JSON.stringify(route.meta) %><% } %> - }<%= (i + 1 === router.routes.length ? '' : ',') %> - <% }) %> +<%= routes %> ] }) diff --git a/lib/build/index.js b/lib/build/index.js index 4957d5105e..1d8c291480 100644 --- a/lib/build/index.js +++ b/lib/build/index.js @@ -9,10 +9,9 @@ const hash = require('hash-sum') const pify = require('pify') const webpack = require('webpack') const { createBundleRenderer } = require('vue-server-renderer') -const { join, resolve, sep, posix } = require('path') +const { join, resolve, sep } = require('path') const clientWebpackConfig = require('./webpack/client.config.js') const serverWebpackConfig = require('./webpack/server.config.js') -const basename = posix.basename const remove = pify(fs.remove) const readFile = pify(fs.readFile) const writeFile = pify(fs.writeFile) @@ -111,13 +110,6 @@ exports.build = function * () { if (!this.dev) { yield mkdirp(r(this.dir, '.nuxt/dist')) } - // Resolve custom routes component path - this.options.router.routes.forEach((route) => { - if (route.component.slice(-4) !== '.vue') { - route.component = route.component + '.vue' - } - route.component = r(this.srcDir, route.component) - }) // Generate routes and interpret the template files yield generateRoutesAndFiles.call(this) /* @@ -144,15 +136,6 @@ function * generateRoutesAndFiles () { ** Generate routes based on files */ const files = yield glob('pages/**/*.vue', { cwd: this.srcDir }) - let routes = [] - files.forEach((file) => { - let path = file.replace(/^pages/, '').replace(/index\.vue$/, '/').replace(/\.vue$/, '').replace(/\/{2,}/g, '/') - let name = file.replace(/^pages/, '').replace(/\.vue$/, '').replace(/\/{2,}/g, '/').split('/').slice(1).join('-') - if (basename(path)[0] === '_') return - routes.push({ path: path, component: r(this.srcDir, file), name: name }) - }) - // Concat pages routes and custom routes in this.routes - this.routes = routes.concat(this.options.router.routes) /* ** Interpret and move template files to .nuxt/ */ @@ -192,14 +175,7 @@ function * generateRoutesAndFiles () { templateVars.loading = templateVars.loading + '.vue' } // Format routes for the lib/app/router.js template - templateVars.router.routes = this.routes.map((route) => { - const r = Object.assign({}, route) - r._component = r.component - r._name = '_' + hash(r._component) - r.component = r._name - r.path = r.path.replace(/\\/g, '\\\\') // regex expression in route path escaping for lodash templating - return r - }) + templateVars.router.routes = this.routes = createRoutes(files, this.srcDir, this.options.router.routes) if (files.includes('pages/_app.vue')) { templateVars.appPath = r(this.srcDir, 'pages/_app.vue') } @@ -223,6 +199,48 @@ function * generateRoutesAndFiles () { yield moveTemplates } +function createRoutes (files, srcDir, options = {}) { + let routes = [] + files.forEach((file) => { + let keys = file.replace(/^pages/, '').replace(/\.vue$/, '').replace(/\/{2,}/g, '/').split('/').slice(1) + let route = { name: '', path: '', component: r(srcDir, file), _name: null } + let parent = routes + keys.forEach((key, i) => { + route.name = route.name ? route.name + (key === 'index' ? '' : '-' + key.replace('_', '')) : key.replace('_', '') + let child = _.find(parent, { name: route.name }) + if (child) { + if (!child.children) { + child.children = [] + } + parent = child.children + } else { + route.path = route.path + (key === 'index' ? (i > 0 ? '' : '/') : '/' + key.replace('_', ':')) + } + }) + route._name = '_' + hash(route.component) + // Update path with regexp in config + const path = _.result(options, keys.join('.')) + if (path && path.regexp) { + route.path = route.path.replace(_.last(keys).replace('_', ':'), path.regexp) + } + // regex expression in route path escaping for lodash templating + // route.path = route.path.replace(/\\/g, '\\\\') + parent.push(route) + }) + return cleanChildrenRoutes(routes) +} + +function cleanChildrenRoutes (routes, isChild = false) { + routes.forEach((route) => { + route.path = (isChild) ? route.path.replace('/', '') : route.path + if (route.children) { + delete route.name + route.children = cleanChildrenRoutes(route.children, true) + } + }) + return routes +} + function getWebpackClientConfig () { return clientWebpackConfig.call(this) }