diff --git a/README.md b/README.md index f0487f6..817ae3e 100755 --- a/README.md +++ b/README.md @@ -158,6 +158,61 @@ You can combine sitemap and sitemap index configurations. } ``` +### Enable static routes filtering by route component config + +Default route component with property `sitemap: true` will mark corresponding route to be included in sitemap. +Routes without this setting will be ignored. + +```js +// nuxt.config.js + +{ + modules: [ + '@nuxtjs/sitemap' + ], + sitemap_filter: true, + sitemap: { + // custom configuration + } +} +``` + +```js +// route component +const Component = { + sitemap: true, + template: '
Hello!
' +} + +// vue-router config +const router = new VueRouter({ + routes: [ + { path: '/hello', component: Component }, + ] +}) +``` + +Single File Components are supported (experimental, tested with Nuxt.js). + +```js +// @/components/Hello.vue + + + +// vue-router config +const router = new VueRouter({ + routes: [ + { path: '/hello', component: '@/components/Hello.vue' }, + ] +}) +``` + ## Sitemap Options ### `routes` (optional) - array | function diff --git a/lib/module.js b/lib/module.js index 5d21f1d..5a5b590 100644 --- a/lib/module.js +++ b/lib/module.js @@ -25,7 +25,7 @@ module.exports = function module(moduleOptions) { // Init static routes nuxtInstance.extendRoutes(routes => { // Create a cache for static routes - globalCache.staticRoutes = getStaticRoutes(routes) + globalCache.staticRoutes = getStaticRoutes.call(nuxtInstance, routes) // On run cmd "build" if (!nuxtInstance.options.dev) { diff --git a/lib/routes.js b/lib/routes.js index 79c3fe8..075d2d3 100644 --- a/lib/routes.js +++ b/lib/routes.js @@ -1,3 +1,4 @@ +const fs = require('fs') const { Minimatch } = require('minimatch') /** @@ -23,8 +24,12 @@ function excludeRoutes(patterns, routes) { * @returns {string[]} */ function getStaticRoutes(router) { + const nuxtInstance = this + // Get all static routes and ignore dynamic routes - return flattenRoutes(router).filter(({ url }) => !url.includes(':') && !url.includes('*')) + return flattenRoutes(router) + .filter(({ url }) => !url.includes(':') && !url.includes('*')) + .filter(nuxtInstance.options.sitemap_filter === true ? _filter(nuxtInstance.options.alias) : route => route) } /** @@ -50,4 +55,52 @@ function flattenRoutes(router, path = '', routes = []) { return routes } +function _filter(aliases) { + const prop = 'sitemap' + const value = true + const aliasesKeys = Object.keys(aliases || {}).join('|') + const reAliasReplacer = aliasesKeys && new RegExp(`^(${aliasesKeys})(.)`, 'g') + const aliasReplacer = (_s, alias, char) => aliases[alias] + ((char !== '/' && char !== '\\' && '/') || '') + char + const normalizeComponentPath = pathName => + (reAliasReplacer && pathName && pathName.replace(reAliasReplacer, aliasReplacer)) || pathName + + const extractComponentData = (text, ...exp) => { + return exp + .filter(re => re) + .reduce((out, re) => { + if (out) { + out = out.match(re) + return (out && out[1]) || void 0 + } + }, text) + } + + const re0 = /\.vue$/ + const re1 = /]*>([\s\S]*?)<\/script>/ + const re2 = /export\s+default\s+({[\s\S]*?})[^}{]*$/ + const re3 = new RegExp(prop + '\\s*:\\s*([^,\\s}]+)') + + const filterByComponentConfig = component => { + if (component) { + if (typeof component === 'string') { + const componentPath = normalizeComponentPath(component) + + if (componentPath) { + try { + return ( + extractComponentData(fs.readFileSync(componentPath, 'utf8'), re0.test(componentPath) && re1, re2, re3) === + value + '' + ) + } catch (e) {} + } + } else if (typeof component === 'object') { + return (component.default || component)[prop] === value + } + } + return false + } + + return ({ component }) => filterByComponentConfig(component) +} + module.exports = { excludeRoutes, getStaticRoutes }