Search code examples
nuxt.jsseoamazon-cloudfrontcanonical-linkcanonicalization

Nuxtjs canonical URL are getting overridden on production


I've a nuxt application, that is deployed using S3 and CF on AWS. The canonical URL is getting changed on production, but working correctly on localhost. Here is my folder structure:

enter image description here

ISSUE:

Inside these pages I've added head() function and added canonical tags custom to each page. Say, For ./blogs home page, below is the code:

  head() {
    return {
      title: 'StackWealth Blog: Financial Insights & Investment Tips',
      meta: [
        {
          hid: 'description',
          name: 'description',
          content: '...'
        }
      ],
      link: [
        {
          hid: 'canonical',
          rel: 'canonical',
          href: `https://stackwealth.in/blogs`
        }
      ]
    };
  },

If I check this on localhost, the link tag is coming correctly. But as soon as I build and deploy to production, this URL automatically get replaced by https://stackwealth.in/ i.e. removing route names from the host URL.

Here is my nuxt.config.js:

import { getBlogRoutes } from './utils';
require('dotenv').config();


export default {
  ssr: true,
  server: {
    port: process.env.PORT || 5100,
    host: '0.0.0.0' // default: localhost
  },
  head: {
    title: '...',
    meta: [
      {
        charset: 'utf-8'
      },
      {
        hid: 'description',
        name: 'description',
        content: '...'          
      },
      ...
    ],
    link: [
      {
        rel: 'icon',
        type: 'image/x-icon',
        href: '/favicon.png'
      }
    ]
  },
  css: [
    '@/assets/scss/app.scss'
  ],
  plugins: [...],
  buildModules: ['nuxt-compress'],
  modules: [
   ...
  ],
  generate: {
    routes: () => getBlogRoutes() /// there is Util function that pull all dynamic URLs
  },
  ...  
};

Expectations:

The URL inside href of <link rel="canonical" href="..."> should be the link of page instead of the host URL.


Solution

  • So basically, the page was loading with a 403 error

    ------ Error page for 403:--------
    Error Caching Minimum TTL   10s
    Response Page Path /index.html
    HTTP Response Code  200
    ---------------------
    

    Since I've subdirectories such as http://www.example.com/about/. The index.html needs to be added after the subdirectory i.e "https://www.example.com/about/index.html" so the page will load without 403 errors.

    So for this I've done a few steps.

    1. All the URLs should end with a trailing /. i.e., https://example.co/about should be https://example.co/about/. This can be done by adding trailingSlash: true inside router key of nuxt.config.js. Don't forget to change all <NuxtLink to=""> code inside your HTML or if you're using this.$route.path('')
    2. Add a redirect.js file inside ./middleware/ of the project and include this file again in nuxt.config.js inside serverMiddleware key. This file will contain the code to redirect all the URL that are not ending with / to the URL ending with /. Check code below.
    3. Now on AWS I've followed this documentation to create Lambda@Edge function for redirection.

    PS - Make sure while editing the AWS Lambda you are saving the details. Also, somehow L@E Node.js 18.x was throwing ES6 module error, so use export const handler = async () => {} instead of exports.handler = async () => {}. Weird but yeah!

    redirect.js

    const redirect= (req, res, next) => {
      const uri = req.url;
      if (!uri.endsWith('/')) {
        res.writeHead(301, { Location: uri + '/' });
        res.end();
      } else {
        next();
      }
    };
    
    export default redirect;