diff --git a/packages/builder/src/builder.js b/packages/builder/src/builder.js index 64449a6980..39a055d37e 100644 --- a/packages/builder/src/builder.js +++ b/packages/builder/src/builder.js @@ -337,12 +337,14 @@ export default class Builder { async resolveRoutes ({ templateVars }) { consola.debug('Generating routes...') + const { routeNameSplitter, trailingSlash } = this.options.router if (this._defaultPage) { templateVars.router.routes = createRoutes({ files: ['index.vue'], srcDir: this.template.dir + '/pages', - routeNameSplitter: this.options.router.routeNameSplitter + routeNameSplitter, + trailingSlash }) } else if (this._nuxtPages) { // Use nuxt.js createRoutes bases on pages/ @@ -359,8 +361,9 @@ export default class Builder { files: Object.values(files), srcDir: this.options.srcDir, pagesDir: this.options.dir.pages, - routeNameSplitter: this.options.router.routeNameSplitter, - supportedExtensions: this.supportedExtensions + routeNameSplitter, + supportedExtensions: this.supportedExtensions, + trailingSlash }) } else { // If user defined a custom method to create routes templateVars.router.routes = this.options.build.createRoutes( diff --git a/packages/config/src/config/router.js b/packages/config/src/config/router.js index 200c22bfc8..8789206755 100644 --- a/packages/config/src/config/router.js +++ b/packages/config/src/config/router.js @@ -12,5 +12,6 @@ export default () => ({ parseQuery: false, stringifyQuery: false, fallback: false, - prefetchLinks: true + prefetchLinks: true, + trailingSlash: undefined }) diff --git a/packages/config/test/__snapshots__/options.test.js.snap b/packages/config/test/__snapshots__/options.test.js.snap index e86ab8530b..df82490459 100644 --- a/packages/config/test/__snapshots__/options.test.js.snap +++ b/packages/config/test/__snapshots__/options.test.js.snap @@ -322,6 +322,7 @@ Object { "routes": Array [], "scrollBehavior": null, "stringifyQuery": false, + "trailingSlash": undefined, }, "server": Object { "host": "localhost", diff --git a/packages/config/test/config/__snapshots__/index.test.js.snap b/packages/config/test/config/__snapshots__/index.test.js.snap index f6870e0198..6fd7695c67 100644 --- a/packages/config/test/config/__snapshots__/index.test.js.snap +++ b/packages/config/test/config/__snapshots__/index.test.js.snap @@ -289,6 +289,7 @@ Object { "routes": Array [], "scrollBehavior": null, "stringifyQuery": false, + "trailingSlash": undefined, }, "server": Object { "host": "localhost", @@ -618,6 +619,7 @@ Object { "routes": Array [], "scrollBehavior": null, "stringifyQuery": false, + "trailingSlash": undefined, }, "server": Object { "host": "localhost", diff --git a/packages/utils/src/route.js b/packages/utils/src/route.js index 5beeeadd2d..a55ad5be53 100644 --- a/packages/utils/src/route.js +++ b/packages/utils/src/route.js @@ -136,7 +136,8 @@ export const createRoutes = function createRoutes ({ srcDir, pagesDir = '', routeNameSplitter = '-', - supportedExtensions = ['vue', 'js'] + supportedExtensions = ['vue', 'js'], + trailingSlash }) { const routes = [] files.forEach((file) => { @@ -173,6 +174,11 @@ export const createRoutes = function createRoutes ({ } } }) + if (trailingSlash !== undefined) { + route.pathToRegexpOptions = { ...route.pathToRegexpOptions, strict: true } + route.path = route.path.replace(/\/+$/, '') + (trailingSlash ? '/' : '') + } + parent.push(route) }) diff --git a/packages/utils/test/__snapshots__/route.test.js.snap b/packages/utils/test/__snapshots__/route.test.js.snap index 7ac1ccbc04..f65199dd84 100644 --- a/packages/utils/test/__snapshots__/route.test.js.snap +++ b/packages/utils/test/__snapshots__/route.test.js.snap @@ -119,3 +119,178 @@ Array [ }, ] `; + +exports[`util: route util: route create createRoutes should enforce trailing slashes when configured to 1`] = ` +Array [ + Object { + "chunkName": "pages/parent/index", + "component": "/some/nuxt/app/pages/parent/index.vue", + "name": "parent", + "path": "/parent/", + "pathToRegexpOptions": Object { + "strict": true, + }, + }, + Object { + "chunkName": "pages/snake_case_route", + "component": "/some/nuxt/app/pages/snake_case_route.vue", + "name": "snake_case_route", + "path": "/snake_case_route/", + "pathToRegexpOptions": Object { + "strict": true, + }, + }, + Object { + "chunkName": "pages/parent/child/index", + "component": "/some/nuxt/app/pages/parent/child/index.vue", + "name": "parent-child", + "path": "/parent/child/", + "pathToRegexpOptions": Object { + "strict": true, + }, + }, + Object { + "chunkName": "pages/parent/child/test", + "component": "/some/nuxt/app/pages/parent/child/test.vue", + "name": "parent-child-test", + "path": "/parent/child/test/", + "pathToRegexpOptions": Object { + "strict": true, + }, + }, + Object { + "children": Array [ + Object { + "chunkName": "pages/another_route/_id", + "component": "/some/nuxt/app/pages/another_route/_id.vue", + "name": "another_route-id", + "path": "", + "pathToRegexpOptions": Object { + "strict": true, + }, + }, + ], + "chunkName": "pages/another_route/_id", + "component": "/some/nuxt/app/pages/another_route/_id.vue", + "name": "another_route-id", + "path": "/another_route/:id?/", + "pathToRegexpOptions": Object { + "strict": true, + }, + }, + Object { + "chunkName": "pages/subpage/_param", + "component": "/some/nuxt/app/pages/subpage/_param.vue", + "name": "subpage-param", + "path": "/subpage/:param?/", + "pathToRegexpOptions": Object { + "strict": true, + }, + }, + Object { + "chunkName": "pages/index", + "component": "/some/nuxt/app/pages/index.vue", + "name": "index", + "path": "/", + "pathToRegexpOptions": Object { + "strict": true, + }, + }, + Object { + "chunkName": "pages/_param", + "component": "/some/nuxt/app/pages/_param.vue", + "name": "param", + "path": "/:param/", + "pathToRegexpOptions": Object { + "strict": true, + }, + }, +] +`; + +exports[`util: route util: route create createRoutes should remove trailing slashes when configured to 1`] = ` +Array [ + Object { + "chunkName": "pages/index", + "component": "/some/nuxt/app/pages/index.vue", + "name": "index", + "path": "", + "pathToRegexpOptions": Object { + "strict": true, + }, + }, + Object { + "chunkName": "pages/parent/index", + "component": "/some/nuxt/app/pages/parent/index.vue", + "name": "parent", + "path": "/parent", + "pathToRegexpOptions": Object { + "strict": true, + }, + }, + Object { + "chunkName": "pages/snake_case_route", + "component": "/some/nuxt/app/pages/snake_case_route.vue", + "name": "snake_case_route", + "path": "/snake_case_route", + "pathToRegexpOptions": Object { + "strict": true, + }, + }, + Object { + "chunkName": "pages/parent/child/index", + "component": "/some/nuxt/app/pages/parent/child/index.vue", + "name": "parent-child", + "path": "/parent/child", + "pathToRegexpOptions": Object { + "strict": true, + }, + }, + Object { + "chunkName": "pages/parent/child/test", + "component": "/some/nuxt/app/pages/parent/child/test.vue", + "name": "parent-child-test", + "path": "/parent/child/test", + "pathToRegexpOptions": Object { + "strict": true, + }, + }, + Object { + "children": Array [ + Object { + "chunkName": "pages/another_route/_id", + "component": "/some/nuxt/app/pages/another_route/_id.vue", + "name": "another_route-id", + "path": "", + "pathToRegexpOptions": Object { + "strict": true, + }, + }, + ], + "chunkName": "pages/another_route/_id", + "component": "/some/nuxt/app/pages/another_route/_id.vue", + "path": "/another_route/:id?", + "pathToRegexpOptions": Object { + "strict": true, + }, + }, + Object { + "chunkName": "pages/subpage/_param", + "component": "/some/nuxt/app/pages/subpage/_param.vue", + "name": "subpage-param", + "path": "/subpage/:param?", + "pathToRegexpOptions": Object { + "strict": true, + }, + }, + Object { + "chunkName": "pages/_param", + "component": "/some/nuxt/app/pages/_param.vue", + "name": "param", + "path": "/:param", + "pathToRegexpOptions": Object { + "strict": true, + }, + }, +] +`; diff --git a/packages/utils/test/route.test.js b/packages/utils/test/route.test.js index 4b66688b22..ee2e58edab 100644 --- a/packages/utils/test/route.test.js +++ b/packages/utils/test/route.test.js @@ -194,5 +194,15 @@ describe('util: route', () => { const routesResult = createRoutes({ files, srcDir, pagesDir }) expect(routesResult).toMatchSnapshot() }) + + test.posix('createRoutes should enforce trailing slashes when configured to', () => { + const routesResult = createRoutes({ files, srcDir, pagesDir, trailingSlash: true }) + expect(routesResult).toMatchSnapshot() + }) + + test.posix('createRoutes should remove trailing slashes when configured to', () => { + const routesResult = createRoutes({ files, srcDir, pagesDir, trailingSlash: false }) + expect(routesResult).toMatchSnapshot() + }) }) })