Search code examples
vue.jsnuxt.jsvue-mixin

Nuxt add global plugins memory leakage issue


I'm on Nuxt 2.13 universal mode, and I have serious memory usage and leakage!!

so as I was looking for related issues, I found this in Nuxt Docs Plugins - NuxtJS :

Don't use Vue.use(), Vue.component(), and globally, don't plug anything in Vue inside this function, dedicated to Nuxt injection. It will cause a memory leak on the server-side.

can anyone tell me what that means??

I'm currently using many external plugins and some globally added mixins by vue.component() and vue.use() . may them be the problem?? (i also have an utils.js mixin file that includes many methods and computed data that is added globally to nuxt.config)

some of my plugins and mixins that added globally to nuxt.config.js file :

// Vuetify 2
import Vue from 'vue'
import Vuetify from 'vuetify'
import 'vuetify/dist/vuetify.min.css'
import '@mdi/font/css/materialdesignicons.css' // Ensure you are using css-loader version "^2.1.1"
import 'font-awesome/css/font-awesome.min.css'
import '@fortawesome/fontawesome-free/css/all.css'
import colors from "vuetify/es5/util/colors";
import '~/assets/vuetify.scss'
// let siteDirection = process.env.SITE_DIRECTION

Vue.use(Vuetify)

export default ctx => {
  const vuetify = new Vuetify({
    rtl: process.env.SITE_DIRECTION === 'rtl' ,
    customVariables: ['~/assets/variables.scss','~/assets/colors.scss'],
    icons: {
      iconfont: 'mdi', // default - only for display purposes
    },
    theme: {
      dark: false, // From 2.0 You have to select the theme dark or light here
      themes: {
        dark: {
          primary: colors.deepPurple.lighten3,
          accent: colors.deepPurple.accent3,
          secondary: colors.amber.darken3,
          info: colors.teal.lighten1,
          warning: colors.amber.base,
          error: colors.deepOrange.accent4,
          success: colors.green.accent4
        }
      }
    }
  })

  ctx.app.vuetify = vuetify
  ctx.$vuetify = vuetify.framework
}

// Vue-Glide Package
import Vue from 'vue'
import { Glide, GlideSlide } from 'vue-glide-js'

Vue.component("vue-glide", Glide)
Vue.component("vue-glide-slide", GlideSlide)

// Noty package
import Vue from "vue";
import Noty from "noty";

Vue.prototype.$noty = (type, text) => new Noty({
    layout:process.env.SITE_DIRECTION === 'rtl' ? 'bottomLeft' : 'bottomRight',
    type,
    text,
    timeout: 5000
});

// vue-product-zoomer package
import Vue from 'vue'
import ProductZoomer from 'vue-product-zoomer'
Vue.use(ProductZoomer)

my Mixins are also added the default way:

import Vue from 'vue'

const FormattedPrice = {
    install(Vue){
      Vue.mixin({
        methods:{
          formattedPrice(price,options){
            if(price !== null && price !== undefined){
              if(typeof price === 'object'){
                let min = price.min ? Number(price.min).toLocaleString() : 0
                let max = price.min ? Number(price.max).toLocaleString() : 0
                return min + ' - ' + max + (options && options.noSign ? '' : this.currencySign)
              }else{
                // try {
                //   return price.toString().replace(/\B(?<!\.\d*)(?=(\d{3})+(?!\d))/g, ",") + this.currencySign
                //   // return price.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",") + this.currencySign
                // } catch (error) {
                //   return Number(price).toLocaleString() + this.currencySign
                // }
                return Number(price).toLocaleString() + (options && options.noSign ? '' : this.currencySign)
              }
            }
            return '...' + (options && options.noSign ? '' : this.currencySign)
          }
        },
        computed:{
          currencySign(){
            return ' ' + this.shopInfo.currency.sign
          }
        }
      })
    }
  }
  
  Vue.use(FormattedPrice)

Solution

  • For your question:

    Don't use Vue.use(), Vue.component(), and globally, don't plug anything in Vue inside this function, dedicated to Nuxt injection. It will cause a memory leak on the server-side.

    See this PR, which is the reason for that warning.

    A more clear explanation would be that you should not call Vue.use() or Vue.component() from inside an exported plugin function. You should place the calls in the global scope, and simply apply them to the context.

    Where I believe you're getting a memory leak is with calling new Vuetify() from inside the exported function. It's entirely possible that they are calling Vue.use() or Vue.component() as a side effect to that call.

    You should instead place that call in the global scope. If this doesn't work, then you may want to consider creating a minimum reproducible example and opening an issue on the Nuxt GitHub repo.

    // Vuetify 2
    import Vue from 'vue'
    import Vuetify from 'vuetify'
    import 'vuetify/dist/vuetify.min.css'
    import '@mdi/font/css/materialdesignicons.css' // Ensure you are using css-loader version "^2.1.1"
    import 'font-awesome/css/font-awesome.min.css'
    import '@fortawesome/fontawesome-free/css/all.css'
    import colors from "vuetify/es5/util/colors";
    import '~/assets/vuetify.scss'
    // let siteDirection = process.env.SITE_DIRECTION
    
    Vue.use(Vuetify)
    
    const vuetify = new Vuetify({
        rtl: process.env.SITE_DIRECTION === 'rtl' ,
        customVariables: ['~/assets/variables.scss','~/assets/colors.scss'],
        icons: {
          iconfont: 'mdi', // default - only for display purposes
        },
        theme: {
          dark: false, // From 2.0 You have to select the theme dark or light here
          themes: {
            dark: {
              primary: colors.deepPurple.lighten3,
              accent: colors.deepPurple.accent3,
              secondary: colors.amber.darken3,
              info: colors.teal.lighten1,
              warning: colors.amber.base,
              error: colors.deepOrange.accent4,
              success: colors.green.accent4
            }
          }
        }
    })
    
    export default ctx => {
      
    
      ctx.app.vuetify = vuetify
      ctx.$vuetify = vuetify.framework
    }