{"id":377,"date":"2020-06-30T09:16:20","date_gmt":"2020-06-30T07:16:20","guid":{"rendered":"https:\/\/nubisoft.io\/blog\/?p=377"},"modified":"2023-06-05T11:30:45","modified_gmt":"2023-06-05T09:30:45","slug":"how-to-multiple-subdomains-nuxt-js","status":"publish","type":"post","link":"https:\/\/nubisoft.io\/blog\/how-to-multiple-subdomains-nuxt-js\/","title":{"rendered":"How to handle multiple domains and subdomains in your Nuxt.js project"},"content":{"rendered":"\n<p><a rel=\"noreferrer noopener\" href=\"https:\/\/nuxtjs.org\/\" target=\"_blank\">NuxtJS<\/a> is a framework based on <a rel=\"noreferrer noopener\" href=\"https:\/\/vuejs.org\/\" target=\"_blank\">Vue.js<\/a> to create applications that can be everything from static landing pages to enterprise web applications. My favorite target is the server-side rendered website. We get all the benefits of the Vue.js ecosystem with SEO optimization and static page speed on different devices.<\/p>\n\n\n\n<p>One of the not obvious part for of Nuxt for typical Vue.js developer is router configuration:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p><em>Nuxt.js automatically generates the&nbsp;<\/em><a href=\"https:\/\/github.com\/vuejs\/vue-router\">vue-router<\/a><em>&nbsp;configuration based on your file tree of Vue files inside the&nbsp;<\/em><code>pages<\/code><em>&nbsp;directory.<\/em><\/p>\n<cite><a href=\"https:\/\/nuxtjs.org\/guide\/routing\">https:\/\/nuxtjs.org\/guide\/routing<\/a><\/cite><\/blockquote>\n\n\n\n<p>It means that we don&#8217;t maintain <code>router.js<\/code> file with complete list of routing. So what we can do if we need nonstandard behavior of our application? Handle multiple domains or subdomains for instance? In my case I want a separate page components for subdomains, because they are completely different to the main page and I want all code base  to look clean. Let&#8217;s see how to do that!<\/p>\n\n\n\n<p>Let&#8217;s start with an empty Nuxt.js project and create <code>subdomain1<\/code> and <code>subdomain2<\/code> sub-directories with <code>index.vue<\/code> components  in pages folder (read how to build<a href=\"https:\/\/nubisoft.io\/blog\/robust-ci-cd-pipelines-for-node-based-projects\/\" data-type=\"post\" data-id=\"289\"> robust CI\/CD pipeline for such project here<\/a>):<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"297\" height=\"165\" src=\"https:\/\/nubisoft.io\/blog\/wp-content\/uploads\/2020\/06\/Zrzut-ekranu-2020-06-29-o-19.00.53.png\" alt=\"\" class=\"wp-image-419\"\/><\/figure>\n<\/div>\n\n\n<p>When we start the project with standard configuration these pages are available at the following URLs:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>http:\/\/localhost:3000<\/code><\/li>\n\n\n\n<li><code>http:\/\/localhost:3000\/subdomain1<\/code><\/li>\n\n\n\n<li><code>http:\/\/localhost:3000\/subdomain2<\/code><\/li>\n<\/ul>\n\n\n\n<p>But my goal is to make them available after deploying to web server under URLs listed below:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>http:\/\/nubisoft.io<\/code><\/li>\n\n\n\n<li><code>http:\/\/subdomain1.nubisoft.io<\/code><\/li>\n\n\n\n<li><code>http:\/\/subdomain2.nubisoft.io<\/code><\/li>\n<\/ul>\n\n\n\n<p>In your local environment open <code>\/etc\/hosts<\/code> file (or <code>%SystemRoot%\\system32\\drivers\\etc\\hosts<\/code> on Windows) and add lines for testing purposes:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"yaml\" data-enlighter-theme=\"monokai\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">127.0.0.1 subdomain1.nubisoft.io\n127.0.0.1 subdomain2.nubisoft.io<\/pre>\n\n\n\n<p>To change the default configuration of Nuxt router install <a rel=\"noreferrer noopener\" href=\"https:\/\/github.com\/nuxt-community\/router-module\" target=\"_blank\">@nuxtjs\/router<\/a> module:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">$ npm install --save-dev @nuxtjs\/router<\/pre>\n\n\n\n<p>Next add just installed build module to <code>nuxt.config.js<\/code> and set location and file name of router configuration which we will create later:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"js\" data-enlighter-theme=\"monokai\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">buildModules: [\n    \/\/ Doc: https:\/\/github.com\/nuxt-community\/eslint-module\n    '@nuxtjs\/eslint-module',\n    [\n      '@nuxtjs\/router',\n      {\n        path: 'router',\n        fileName: 'index.js',\n        keepDefaultRouter: true,\n      },\n    ],\n  ],<\/pre>\n\n\n\n<p>The <code>keepDefaultRouter<\/code> property disables or enables automatic generation of router configuration based on your file tree. It&#8217;s time to add <code>router\/index.js<\/code> file to the project and paste code with <code>console.log()<\/code> to preview the default router options:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"js\" data-enlighter-theme=\"monokai\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">import Vue from 'vue';\nimport Router from 'vue-router';\n\nVue.use(Router);\n\nexport function createRouter(ssrContext, createDefaultRouter, routerOptions) {\n  const options = routerOptions || createDefaultRouter(ssrContext).options;\n\n  console.log(options.routes);\n\n  return new Router({\n    ...options,\n    routes: options.routes,\n  });\n}<\/pre>\n\n\n\n<p>After starting our project the browser console should print routes list as we would expect in standard Nuxt.js project:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"js\" data-enlighter-theme=\"monokai\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">[\n  {\n    path: '\/subdomain1',\n    component: [Function: _7148fb8a],\n    name: 'subdomain1'\n  },\n  {\n    path: '\/subdomain2',\n    component: [Function: _5c4034fc],\n    name: 'subdomain2'\n  },\n  { path: '\/', component: [Function: _5eb7a297], name: 'index' }\n]<\/pre>\n\n\n\n<p>Now we can implement<code data-enlighter-language=\"generic\" class=\"EnlighterJSRAW\"> fixRoutes()<\/code> function which will change paths in subdomain routes:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"js\" data-enlighter-theme=\"monokai\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">export function createRouter(ssrContext, createDefaultRouter, routerOptions) {\n  const options = routerOptions || createDefaultRouter(ssrContext).options;\n  const hostname = ssrContext ? ssrContext.req.headers.host : location.host;\n\n  return new Router({\n    ...options,\n    routes: fixRoutes(options.routes, hostname),\n  });\n}\n\nfunction fixRoutes(defaultRoutes, hostname) {\n  if (hostname.includes('subdomain1')) return subdomain1Routes(defaultRoutes);\n  if (hostname.includes('subdomain2')) return subdomain2Routes(defaultRoutes);\n  return nubisoftRoutes(defaultRoutes);\n}\n\nfunction nubisoftRoutes(defaultRoutes) {\n  return defaultRoutes.filter(r => r.name !== 'subdomain1' &amp;&amp; 'subdomain2');\n}\n\nfunction subdomain1Routes(defaultRoutes) {\n  const route = defaultRoutes.find(r => r.name === 'subdomain1');\n  route.path = '\/';\n  return [route];\n}\n\nfunction subdomain2Routes(defaultRoutes) {\n  const route = defaultRoutes.find(r => r.name === 'subdomain2');\n  route.path = '\/';\n  return [route];\n}<\/pre>\n\n\n\n<p>The <code>hostname<\/code> variable is set depending on whether the source code is running on server-side or in browser so we can use request header or location.host property, respectively. If we detect one of our subdomains we should find the proper route and replace path property. After applying the above changes, we should see our separate components while visiting http:\/\/subdomain1.nubisoft.io<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full is-resized\"><img decoding=\"async\" src=\"https:\/\/nubisoft.io\/blog\/wp-content\/uploads\/2020\/06\/Zrzut-ekranu-2020-06-29-o-20.24.27.png\" alt=\"\" class=\"wp-image-431\" width=\"500\" srcset=\"https:\/\/nubisoft.io\/blog\/wp-content\/uploads\/2020\/06\/Zrzut-ekranu-2020-06-29-o-20.24.27.png 630w, https:\/\/nubisoft.io\/blog\/wp-content\/uploads\/2020\/06\/Zrzut-ekranu-2020-06-29-o-20.24.27-300x240.png 300w\" sizes=\"(max-width: 630px) 100vw, 630px\" \/><\/figure>\n<\/div>\n\n\n<p>That&#8217;s it! If you have some cache mechanism be sure it is configured properly &#8211; i.e. it can&#8217;t use only path property from routes list. The complete example is available on GitHub: <a href=\"https:\/\/github.com\/nubisoft\/nuxtjs-multiple-domains\">https:\/\/github.com\/nubisoft\/nuxtjs-multiple-domains<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>NuxtJS is a framework based on Vue.js to create applications that can be everything from static landing pages to enterprise web applications. My favorite target is the server-side rendered website. We get all the benefits of the Vue.js ecosystem with SEO optimization and static page speed on different devices. One of the not obvious part [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":410,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_case_study_excerpt":"","footnotes":""},"categories":[68,3],"tags":[69,71,70],"class_list":["post-377","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-javascript","category-software-development","tag-javascript","tag-nuxt-js","tag-vue-js"],"_links":{"self":[{"href":"https:\/\/nubisoft.io\/blog\/wp-json\/wp\/v2\/posts\/377","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/nubisoft.io\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/nubisoft.io\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/nubisoft.io\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/nubisoft.io\/blog\/wp-json\/wp\/v2\/comments?post=377"}],"version-history":[{"count":38,"href":"https:\/\/nubisoft.io\/blog\/wp-json\/wp\/v2\/posts\/377\/revisions"}],"predecessor-version":[{"id":1268,"href":"https:\/\/nubisoft.io\/blog\/wp-json\/wp\/v2\/posts\/377\/revisions\/1268"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/nubisoft.io\/blog\/wp-json\/wp\/v2\/media\/410"}],"wp:attachment":[{"href":"https:\/\/nubisoft.io\/blog\/wp-json\/wp\/v2\/media?parent=377"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/nubisoft.io\/blog\/wp-json\/wp\/v2\/categories?post=377"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/nubisoft.io\/blog\/wp-json\/wp\/v2\/tags?post=377"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}