Nuxt full static generated page issue with cyrillic URI

676 Views Asked by At

in my multilangague nuxt app with static target, i have an issue related to the static page generated:

the pages that need dynamic data on generation via asyncData and with ciryllic endocoedURI they can be accessed in 2 ways in the final dist:

http://localhost:3000/bg/%D0%B2%D0%B8%D0%BB%D0%B8-%D1%85%D0%B0%D0%BB%D0%BA%D0%B8%D0%B4%D0%B8%D0%BA%D0%B8 This URL fallback to the SPA page (the issue)

http://localhost:3000/bg/%D0%B2%D0%B8%D0%BB%D0%B8-%D1%85%D0%B0%D0%BB%D0%BA%D0%B8%D0%B4%D0%B8%D0%BA%D0%B8/ This is full static page

The problem is the "/" at the end of the second link and i don't know why this happens.

I use nuxt-i18n on my project (latest version) The path configuration inside my component is as follow:

nuxtI18n: {
        paths: {
            en: encodeURI(`/${process.env.VILLAS_EN}`),
            bg: encodeURI(`/${process.env.VILLAS_BG}`),
            ru: encodeURI(`/${process.env.VILLAS_RU}`)
        }
    },

inside the .env file i have these values:

VILLAS_EN = 'villas'
VILLAS_BG = 'вили-халкидики'
VILLAS_RU = 'халкидики-виллы'

Inside nuxt.config.js:

modules: [
    '@nuxtjs/axios'
    ,['nuxt-i18n', {
      strategy: 'prefix_except_default',
      locales: [
        //{ name: 'Italiano', code: 'it', iso: 'it-IT', file: 'it-IT.js' },
        { name: 'Bulgarian', code: 'bg', iso: 'bg-BG', file: 'bg-BG.js' },
        { name: 'Russian', code: 'ru', iso: 'ru-RU', file: 'ru-RU.js' },
        { name: 'English', code: 'en', iso: 'en-US', file: 'en-US.js' },
      ]
      , lazy: true
      , langDir: 'locales/'
      , defaultLocale: 'en'
      //, encodePaths: false
      , seo: true
      //, parsePages: false
      //, pages: i18nConfig.pages
      /*
      , detectBrowserLanguage: {
        useCookie: true,
        cookieKey: 'i18n_redirected',
        onlyOnRoot: true
      }*/
    }]

I honestly don't know how to fix this issue. I made a test adding the final slash at all paths but it doesn't work. Thanks in advance for your help.

Below the complete nuxt.config.js

/*
 ** Load .env configuration base on profile ( development | staging | production )
 */
/*
 ** Vuetify local settings
 */
import colors from 'vuetify/es5/util/colors'
import axios from 'axios'

require('dotenv').config()
// import i18nConfig from './i18n.config'

export default {
  ssr: true,
  target: 'static',

  publicRuntimeConfig: {
    apiBaseUrl: process.env.API_BASE_URL,
    apiBasePath: process.env.API_BASE_PATH,
    baseTitle: process.env.BASE_TITLE || 'SiteTitle',
    pathVillasEn: 'villas',
    pathVillasBg: 'вили-халкидики',
    pathVillasRu: 'халкидики-виллы',
    sendGridApiKey: process.env.SENDGRID_API_KEY,
    recaptcha: {
      siteKey: process.env.RECAPTCHA_SITE_KEY,
    },
    contactFormApi: process.env.CONTACT_FORM_API,
  },

  /*
   ** Headers of the page
   */
  head: {
    // titleTemplate: '%s - ' + process.env.npm_package_name,
    // title: process.env.npm_package_name || '',
    titleTemplate: '%s - SiteTitle',
    title: process.env.BASE_TITLE || '',
    meta: [
      { charset: 'utf-8' },
      { name: 'viewport', content: 'width=device-width, initial-scale=1' },
      { hid: 'description', name: 'description', content: process.env.npm_package_description || '' },
      { 'http-equiv': 'X-UA-Compatible', content: 'IE=edge' },
    ],
    link: [{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }],
  },
  /*
   ** Customize the progress-bar color
   */
  loading: { color: '#f00' },

  /*
   ** Plugins to load before mounting the App
   */
  plugins: [
    '~/plugins/axios',
    '~/plugins/helper',
    '~/plugins/calculator',
    //, '~/plugins/composition-api'
  ],

  /*
   ** Nuxt.js dev-modules
   */
  buildModules: [
    ['@nuxtjs/dotenv', { filename: '.env.' + process.env.NODE_ENV }],
    '@nuxtjs/axios',
    ['@nuxtjs/vuetify', { treeShake: true }],
    ['@nuxtjs/google-analytics', { id: process.env.GOOGLE_ANALYTICS }],
  ],

  /*
   ** Nuxt.js modules
   */
  modules: [
    '@nuxtjs/axios',
    [
      'nuxt-i18n',
      {
        strategy: 'prefix_except_default',
        locales: [
          { name: 'Bulgarian', code: 'bg', iso: 'bg-BG', file: 'bg-BG.js' },
          { name: 'Russian', code: 'ru', iso: 'ru-RU', file: 'ru-RU.js' },
          { name: 'English', code: 'en', iso: 'en-US', file: 'en-US.js' },
        ],
        lazy: true,
        langDir: 'locales/',
        defaultLocale: 'en',
        //, encodePaths: false
        seo: true,
        //, parsePages: false
        //, pages: i18nConfig.pages
        /*
          , detectBrowserLanguage: {
            useCookie: true,
            cookieKey: 'i18n_redirected',
            onlyOnRoot: true
          } */
      },
    ],
    //, '@nuxtjs/sitemap'
    'nuxt-lazy-load',
    '@nuxtjs/robots',
    [
      '@nuxtjs/recaptcha',
      {
        hideBadge: true,
        siteKey: process.env.RECAPTCHA_SITE_KEY,
        version: 3,
      },
    ],
    //, '@nuxtjs/auth'
    //, '@nuxtjs/proxy'
  ],

  /*
   ** Robots.txt
   */
  robots: {
    UserAgent: '*',
    Disallow: '/',
  },

  /*
   ** Purge CSS
   */
  purgeCSS: {
    whitelistPatterns: [/^v-*/, /^theme-*/, /^application--*/],
    whitelistPatternsChildren: [/^v-*/, /^theme-*/, /^application--*/],
    whitelist: ['spacer', 'primary', 'secondary', 'accent', 'error', 'warning', 'info', 'success'],
  },

  /*
   ** Axios configurations
   */
  axios: {
    baseURL: `${process.env.API_BASE_URL}${process.env.API_BASE_PATH}`,
    https: true,
    //   //debug: true,
    //   //proxyHeadersIgnore: ['host', 'accept', 'cf-ray', 'cf-connecting-ip'],
    //   proxyHeaders: false,
    //   https:false,
    //   credentials: false,
    //   proxy: true
  },

  /*
   ** Static HTML generator
   */
  generate: {
    interval: 100,
    crawler: false,
    fallback: '404.html',
    gzip: true,

    async routes() {
      const slugs = []

      async function postRoutes(type, lang = '') {
        const _lang = `/${lang}` || ''
        return await axios
          .post(`${process.env.API_BASE_URL}${_lang}${process.env.API_BASE_PATH}/post-type-list`, {
            postType: type,
          })
          .then((r) => {
            if (r.data.data.type == 'villas') {
              r.data.data.items.map((item) => {
                let slug = ''
                switch (lang) {
                  case 'bg':
                    slug = encodeURI(
                      `${_lang}/${process.env.VILLAS_BG}/${decodeURI(item.slug).toString()}`,
                    ).toString()
                    break
                  case 'ru':
                    slug = encodeURI(
                      `${_lang}/${process.env.VILLAS_RU}/${decodeURI(item.slug).toString()}`,
                    ).toString()
                    break
                  default:
                    slug = encodeURI(
                      `/${process.env.VILLAS_EN}/${decodeURI(item.slug).toString()}`,
                    ).toString()
                    break
                }
                if (slug !== undefined) slugs.push({ route: slug, payload: item })
              })
            }
          })
      }

      await axios
        .all([postRoutes('villas'), postRoutes('villas', 'bg'), postRoutes('villas', 'ru')])
        .then((results) => { })

      return slugs
    },
  },

  /*
   ** Sitemap
   */
  sitemap: {
    hostname: process.env.API_BASE_URL,
    path: '/sitemapindex.xml',
    defaults: {
      changefreq: 'daily',
      priority: 1,
      lastmod: new Date(),
    },
    // notation (basic)
    //, i18n: true
    // nuxt-i18n notation (advanced)
    i18n: {
      locales: ['en', 'bg', 'ru'],
      routesNameSeparator: '___',
    },
  },

  /*
   ** vuetify module configuration
   ** https://github.com/nuxt-community/vuetify-module
   */
  vuetify: {
    customVariables: ['~/assets/variables.scss'],
    treeShake: true,
    defaultAssets: false,
    icons: {
      iconfont: 'mdi',
    },
    theme: {
      dark: false,
      themes: {
        dark: {
          primary: colors.blue.darken2,
          accent: colors.grey.darken3,
          secondary: colors.amber.darken3,
          info: colors.teal.lighten1,
          warning: colors.amber.base,
          error: colors.deepOrange.accent4,
          success: colors.green.accent3,
        },
        light: {
          primary: colors.blue.darken2,
          accent: colors.grey.darken3,
          secondary: colors.amber.darken3,
          info: colors.teal.lighten1,
          warning: colors.amber.base,
          error: colors.deepOrange.accent4,
          success: colors.green.accent3,
        },
      },
    },
  },

  /*
   ** Build configuration
   */
  build: {
    html: {
      minify: {
        collapseBooleanAttributes: true,
        decodeEntities: true,
        minifyCSS: true,
        minifyJS: true,
        processConditionalComments: true,
        removeEmptyAttributes: true,
        removeRedundantAttributes: true,
        trimCustomFragments: true,
        useShortDoctype: true,
        preserveLineBreaks: false,
        collapseWhitespace: true,
      },
    },

    extractCSS: true,

    /*
     ** You can extend webpack config here
     */
    extend(config, ctx) {
      config.node = {
        console: true,
        fs: 'empty',
        net: 'empty',
        tls: 'empty',
      }
    },
    //, analyze: true
  },
}
1

There are 1 best solutions below

3
On

I'm really not sure about this one, but here is the official documentation page of nuxt's traillingSlash: https://nuxtjs.org/docs/2.x/configuration-glossary/configuration-router#trailingslash

I'm not even sure that this is the issue actually. It's maybe coming from somewhere else. Do you have the whole nuxt.config.js configuration ?