diff --git a/README.md b/README.md index 388b452..e873b42 100644 --- a/README.md +++ b/README.md @@ -93,6 +93,20 @@ Can access the default router. Can disable/enable the `pages/` directory into Nuxt. +### `rootDomain` + +- Type: `String` +- Default: `'null'` + +Directory name for the pages of root-domain. + +### `subDomains` + +- Type: `String[]` +- Default: `[]` + +List of directories to hold te pages for your subdomains. + ## Usage This module, by default, disable the `pages/` directory into Nuxt and will use a `router.js` file at your `srcDir` directory: @@ -136,13 +150,21 @@ If you use the module with `{ keepDefaultRouter: true }`, you can access the def :warning: If you are using Nuxt `< 2.15.0`, the parameter `config` is not available. +:warning: If you are using Nuxt Router `< 1.7.0`, the parameter `getRoutesDomainOrSubdomain` is not available. + ```js -export function createRouter(ssrContext, createDefaultRouter, routerOptions, config) { - const options = routerOptions ? routerOptions : createDefaultRouter(ssrContext, config).options +import Vue from 'vue' +import Router from 'vue-router' + +Vue.use(Router) + +export function createRouter(ssrContext, createDefaultRouter, routerOptions, config, getRoutesDomainOrSubdomain) { + const options = routerOptions || createDefaultRouter(ssrContext, config).options + const routes = getRoutesDomainOrSubdomain ? getRoutesDomainOrSubdomain(ssrContext, options.routes) : options.routes return new Router({ ...options, - routes: fixRoutes(options.routes) + routes: fixRoutes(routes) }) } diff --git a/src/module.ts b/src/module.ts index 05b4413..c11cf9e 100644 --- a/src/module.ts +++ b/src/module.ts @@ -12,6 +12,8 @@ export interface ModuleOptions { fileName: string; keepDefaultRouter?: boolean; parsePages?: boolean; + rootDomain?: string; + subDomains?: string[]; } const CONFIG_KEY = 'routerModule' @@ -20,7 +22,9 @@ const nuxtModule: Module = function (moduleOptions) { const DEFAULTS: ModuleOptions = { path: this.options.srcDir, fileName: 'router.js', - keepDefaultRouter: false + keepDefaultRouter: false, + rootDomain: null, + subDomains: [] } const options: ModuleOptions = defu( @@ -37,9 +41,10 @@ const nuxtModule: Module = function (moduleOptions) { const routerFilePath = resolve(options.path, options.fileName) // Check if router file path is defined - if (!existsSync(routerFilePath)) { + if (!existsSync(routerFilePath) && !options.keepDefaultRouter) { logger.warn(`No \`${options.fileName}\` file found in \`${options.path}\`.`) - return + + options.keepDefaultRouter = true } // Add plugin to import router file path as the main template for routing @@ -47,8 +52,12 @@ const nuxtModule: Module = function (moduleOptions) { src: resolve(__dirname, '../templates/plugin.js'), fileName: 'router.js', options: { - routerFilePath: relative(this.options.buildDir, routerFilePath).replace(/\/+|\\+/g, '/'), - keepDefaultRouter: options.keepDefaultRouter + routerFilePath: existsSync(routerFilePath) + ? relative(this.options.buildDir, routerFilePath).replace(/\/+|\\+/g, '/') + : null, + keepDefaultRouter: options.keepDefaultRouter, + rootDomain: options.rootDomain, + subDomains: options.subDomains } }) diff --git a/templates/plugin.js b/templates/plugin.js index 17e429a..3525baa 100644 --- a/templates/plugin.js +++ b/templates/plugin.js @@ -1,5 +1,3 @@ -import { createRouter as customCreateRouter } from '<%= options.routerFilePath %>' - <% if (options.keepDefaultRouter) { %> import { createRouter as createDefaultRouter, routerOptions } from './defaultRouter' <% } else { %> @@ -7,6 +5,92 @@ const createDefaultRouter = null const routerOptions = null <% } %> +<% if (options.routerFilePath) { %> +import { createRouter as customCreateRouter } from '<%= options.routerFilePath %>' +<% } else { %> +import Vue from 'vue' +import Router from 'vue-router' + +Vue.use(Router) + +const customCreateRouter = (ssrContext, createDefaultRouter, routerOptions, config, getRoutesDomainOrSubdomain) => { + const options = routerOptions || createDefaultRouter(ssrContext, config).options + const routes = getRoutesDomainOrSubdomain(ssrContext, options.routes) + + return new Router({ + ...options, + routes + }) +} +<% } %> + export function createRouter(ssrContext, config) { - return customCreateRouter(ssrContext, createDefaultRouter, routerOptions, config) + return customCreateRouter(ssrContext, createDefaultRouter, routerOptions, config, getRoutesDomainOrSubdomain) +} + +const getRoutesDomainOrSubdomain = (ssrContext, routes) => { + const rootDomain = '<%= options.rootDomain %>' + const subdomains = [<%= options.subDomains.map(subdomain => `'${subdomain}'`).join(', ') %>] + const routesDirectory = getRoutesDirectory(ssrContext, rootDomain, subdomains) + + if (!routesDirectory) { + return routes + } + + return routes + .filter(route => { + return !routeIsUnderDirectory(route, [...subdomains, rootDomain].filter(domain => domain !== routesDirectory)) + }) + .map((route) => { + if (!routeIsUnderDirectory(route, routesDirectory)) { + return route + } + + return { + ...route, + path: route.path.substr(routesDirectory.length + 1) || '/', + name: route.name.substr(routesDirectory.length + 1) || 'index' + } + }) +} + +const getRoutesDirectory = (ssrContext, rootDomain, subdomains) => { + let routesDirectory = null + + if (!rootDomain || !subdomains || !subdomains.length) { + return routesDirectory + } + + if (process.server && ssrContext && ssrContext.nuxt && ssrContext.req) { + const req = ssrContext.req + + // get the subdomain from the request host + const matcher = req.headers.host.match(/^(\w+(-\w+)?)\.(localhost|\w+(-\w+)?)(\.\w+)?/) + routesDirectory = matcher[1] || matcher[0] + + // if the subdomain is not in the list of user provided domains, set the root directory to root - domain given by the user + routesDirectory = subdomains.includes(routesDirectory) ? routesDirectory : rootDomain + + // Save to the object that will be sent to the client as inline-script + ssrContext.nuxt.routesDirectory = routesDirectory + } + + // Get what we saved on SSR + if (process.client && window.__NUXT__ && window.__NUXT__.routesDirectory) { + routesDirectory = window.__NUXT__.routesDirectory + } + + return routesDirectory +} + +const routeIsUnderDirectory = (route, directory) => { + const dirs = Array.isArray(directory) ? directory : [directory] + + for (const dir of dirs) { + if (route.path === '/' + dir || route.path.startsWith('/' + dir + '/')) { + return true + } + } + + return false }