Nuxt巨大内存使用/泄漏以及如何预防

2023-12-20

我使用的是 Nuxt v2.13 和 Vuetify v2 ,也在我的默认布局中使用 keep-alive 。随着我的应用程序变得越来越大,我越来越注意到内存问题,因此我的应用程序需要在云服务器上至少大约 4GB RAM 才能构建并正常工作。我四处挖掘,发现了零散的碎片,所以决定分享它们并讨论解决方案。

请根据#numbers 逐一回答

#1 - NuxtLink(vue-router)内存泄漏:其他人发现 vue-router 可能存在泄漏;另外,由于与 nuxt-link 关联的 DOM 将被预取,因此内存使用率也可能很高。所以有人建议使用 html 锚点而不是 nuxt-link ,如下所示:

<template>
  <a href="/mypage" @click.prevent="goTo('mypage')">my page link</a>
</template>

<script>
export default{
  methods:{
    goTo(link){
      this.$router.push(link)
    }
  }
}
</script>

您对这种方法有何看法? Vuetify 怎么样to道具,因为它们像 nuxt-link 一样工作?

<template>
  <v-card to="/mypage" ></v-card>
</template>

#2 - 动态组件加载:由于我的应用程序是双向的并且可以通过以下方式自定义.envfile 中,我必须动态且有条件地延迟加载我的许多组件,如下所示:

<template>
  <component :is="mycomp" />
</template>

<script>
export default{
  computed:{
    mycomp(){
      return import()=>(`@/components/${process.env.SITE_DIR}/mycomp.vue`)
    }
  }
}
</script>

这会导致高内存使用/泄漏吗?

# 3 - Nuxt 事件总线:除了正常之外this.$emit()在我的组件中,有时我不得不使用$nuxt.$emit()。我将它们全部删除beforeDestroy hook :

<script>
export default{
  created:{
    this.$nuxt.$on('myevent', ()=>{
      // do something
    }
  },
  beforeDestroy(){
    this.$nuxt.$off('myevent')
  }
}
</script>

但有人告诉我听众createdhook 将是 SSR 并且不会在 CSR 中被删除beforeDestroy钩。所以我该怎么做?添加if(process.client){} to created ??

# 4 - 全局插件:我发现这个问题 https://github.com/nuxt/nuxt.js/issues/1984#issuecomment-340412232并且this doc https://nuxtjs.org/docs/2.x/directory-structure/plugins/#inject-in-root--context。我在全局添加了我的插件/包,如中所述这个问题 https://stackoverflow.com/questions/66831561/nuxt-add-global-plugins-memory-leakage-issue/66834247#66834247。也是如此vue.use()一个问题 ?我应该使用inject反而?如何?

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

# 5 - Vee 验证泄漏: I read here https://github.com/logaretm/vee-validate/issues/1587#issuecomment-421339419请问,这真的会导致泄漏吗?我正在使用 Vee Validate v3 :

我的 veevalidate.js 全局添加到 nuxt.config.js

import Vue from 'vue'
import {  ValidationObserver, ValidationProvider, setInteractionMode } from 'vee-validate'
import { localize } from 'vee-validate';
import en from 'vee-validate/dist/locale/en.json';
import fa from 'vee-validate/dist/locale/fa.json';

localize({
    en,
    fa
});

setInteractionMode('eager')

let LOCALE = "fa";
Object.defineProperty(Vue.prototype, "locale", {
    configurable: true,
    get() {
        return LOCALE;
    },
    set(val) {
        LOCALE = val;
        localize(val);
    }
});

Vue.component('ValidationProvider', ValidationProvider);
Vue.component("ValidationObserver", ValidationObserver);

我添加到每个页面/组件的 veevalidate mixin 使用了 veevalidate 。 (我使用 mixin 因为我需要使用我的 vuex 状态lang )


import { required, email , alpha , alpha_spaces , numeric , confirmed , password } from 'vee-validate/dist/rules'
import { extend } from 'vee-validate'

export default {
    mounted() {
        extend("required", {
            ...required,
            message: `{_field_} ${this.lang.error_required}`
        });
        extend("email", {
            ...email,
            message: `{_field_} ${this.lang.error_email}`
        });
        extend("alpha", {
            ...alpha,
            message: `{_field_} ${this.lang.error_alpha}`
        });
        extend("alpha_spaces", {
            ...alpha_spaces,
            message: `{_field_} ${this.lang.error_alpha_spaces}`
        });
        extend("numeric", {
            ...numeric,
            message: `{_field_} ${this.lang.error_numeric}`
        });
        extend("confirmed", {
            ...confirmed,
            message: `{_field_} ${this.lang.error_confirmed}`
        });
        extend("decimal", {
            validate: (value, { decimals = '*', separator = '.' } = {}) => {
                if (value === null || value === undefined || value === '') {
                    return {
                        valid: false
                    };
                }
                if (Number(decimals) === 0) {
                    return {
                        valid: /^-?\d*$/.test(value),
                    };
                }
                const regexPart = decimals === '*' ? '+' : `{1,${decimals}}`;
                const regex = new RegExp(`^[-+]?\\d*(\\${separator}\\d${regexPart})?([eE]{1}[-]?\\d+)?$`);
        
                return {
                    valid: regex.test(value),
                };
            },
            message: `{_field_} ${this.lang.error_decimal}`
        })
    }
}

# 6 - 保持活力:正如我之前提到的,我在我的应用程序中使用 keep-alive,它会自我缓存很多东西,并且可能不会破坏/删除插件和事件侦听器。

# 7 - 设置超时:是否需要使用clearTimeout来进行数据清除?

# 8 - 删除插件/包: in this Doc https://v2.vuejs.org/v2/cookbook/avoiding-memory-leaks.html据说有些插件/包即使在组件被销毁后也不会被删除,我怎样才能找到它们?

这是我的包和 nuxt.config

// package.json
{
  "name": "nuxt",
  "version": "1.0.0",
  "private": true,
  "scripts": {
    "dev": "nuxt",
    "build": "nuxt build",
    "start": "nuxt start",
    "generate": "nuxt generate"
  },
  "dependencies": {
    "@nuxt/http": "^0.6.0",
    "@nuxtjs/auth": "^4.9.1",
    "@nuxtjs/axios": "^5.11.0",
    "@nuxtjs/device": "^1.2.7",
    "@nuxtjs/google-gtag": "^1.0.4",
    "@nuxtjs/gtm": "^2.4.0",
    "chart.js": "^2.9.3",
    "cookie-universal-nuxt": "^2.1.4",
    "jquery": "^3.5.1",
    "less-loader": "^6.1.2",
    "nuxt": "^2.13.0",
    "nuxt-user-agent": "^1.2.2",
    "v-viewer": "^1.5.1",
    "vee-validate": "^3.3.7",
    "vue-chartjs": "^3.5.0",
    "vue-cropperjs": "^4.1.0",
    "vue-easy-dnd": "^1.10.2",
    "vue-glide-js": "^1.3.14",
    "vue-persian-datetime-picker": "^2.2.0",
    "vue-product-zoomer": "^3.0.1",
    "vue-slick-carousel": "^1.0.6",
    "vue-sweetalert2": "^3.0.5",
    "vue2-editor": "^2.10.2",
    "vuedraggable": "^2.24.0",
    "vuetify": "^2.3.9"
  },
  "devDependencies": {
    "@fortawesome/fontawesome-free": "^5.15.1",
    "@mdi/font": "^5.9.55",
    "@nuxtjs/dotenv": "^1.4.1",
    "css-loader": "^3.6.0",
    "flipclock": "^0.10.8",
    "font-awesome": "^4.7.0",
    "node-sass": "^4.14.1",
    "noty": "^3.2.0-beta",
    "nuxt-gsap-module": "^1.2.1",
    "sass-loader": "^8.0.2"
  }
}
//nuxt.config.js
const env = require('dotenv').config()
const webpack = require('webpack')

export default {
  mode: 'universal',

  loading: {
    color: 'green',
    failedColor: 'red',
    height: '3px'
  },
  router: {
    // base: process.env.NUXT_BASE_URL || '/' 
  },
  head: {
    title: process.env.SITE_TITLE + ' | ' + process.env.SITE_SHORT_DESC || '',
    meta: [
      { charset: 'utf-8' },
      { name: 'viewport', content: 'width=device-width, initial-scale=1' },
      { hid: 'keywords', name: 'keywords', content: process.env.SITE_KEYWORDS || '' },
      { hid: 'description', name: 'description', content: process.env.SITE_DESCRIPTION || '' },
      { hid: 'robots', name: 'robots', content: process.env.SITE_ROBOTS || '' },
      { hid: 'googlebot', name: 'googlebot', content: process.env.SITE_GOOGLE_BOT || '' },
      { hid: 'bingbot', name: 'bingbot', content: process.env.SITE_BING_BOT || '' },
      { hid: 'og:locale', name: 'og:locale', content: process.env.SITE_OG_LOCALE || '' },
      { hid: 'og:type', name: 'og:type', content: process.env.SITE_OG_TYPE || '' },
      { hid: 'og:title', name: 'og:title', content: process.env.SITE_OG_TITLE || '' },
      { hid: 'og:description', name: 'og:description', content: process.env.SITE_OG_DESCRIPTION || '' },
      { hid: 'og:url', name: 'og:url', content: process.env.SITE_OG_URL || '' },
      { hid: 'og:site_name', name: 'og:site_name', content: process.env.SITE_OG_SITENAME || '' },
      { hid: 'theme-color', name: 'theme-color', content: process.env.SITE_THEME_COLOR || '' },
      { hid: 'msapplication-navbutton-color', name: 'msapplication-navbutton-color', content: process.env.SITE_MSAPP_NAVBTN_COLOR || '' },
      { hid: 'apple-mobile-web-app-status-bar-style', name: 'apple-mobile-web-app-status-bar-style', content: process.env.SITE_APPLE_WM_STATUSBAR_STYLE || '' },
      { hid: 'X-UA-Compatible', 'http-equiv': 'X-UA-Compatible', content: process.env.SITE_X_UA_Compatible || '' }
    ],
    link: [
      { rel: 'icon', type: 'image/x-icon', href: process.env.SITE_FAVICON },
      // { rel: 'shortcut icon', type: 'image/x-icon', href: process.env.SITE_FAVICON },
      { rel: 'canonical', href: process.env.SITE_REL_CANONICAL },
      // { rel: 'stylesheet', href: 'https://cdn.jsdelivr.net/npm/[email protected] /cdn-cgi/l/email-protection/css/font-awesome.min.css' },
    ]
  },
  css: [
      '~/assets/scss/style.scss',
      '~/assets/scss/media.scss',
      '~/assets/scss/customization.scss',
      '~/assets/scss/sweetalert.scss',
      '~/assets/scss/noty.scss',
      '~/assets/scss/flipclock.scss',
      '~/assets/scss/glide.scss',
      '~/assets/scss/sorting.scss',
      '~/assets/scss/cropper.scss',
      '~/assets/scss/transitions.scss',
      '~/assets/scss/product-zoom.scss',
      'vue-slick-carousel/dist/vue-slick-carousel.css'
  ],
  plugins: [
      'plugins/mixins/reqerrors.js',
      'plugins/mixins/user.js',
      'plugins/mixins/language.js',
      'plugins/mixins/shopinfo.js',
      'plugins/mixins/formattedprice.js',
      'plugins/mixins/utils.js',
      'plugins/mixins/cms.js',
      'plugins/mixins/client.js',
      'plugins/mixins/cart.js',
      'plugins/axios.js',
      'plugins/veevalidate.js',
      'plugins/noty.js',
      'plugins/glide.js',
      '@plugins/vuetify',
      '@plugins/vuedraggable',
      '@plugins/vuedraggable',
      '@plugins/vue-slick-carousel.js',
      {src: 'plugins/vuepersiandatepicker.js', mode: 'client'},
      {src: 'plugins/cropper.js', mode: 'client'},
      {src: 'plugins/vue-product-zoomer.js', mode: 'client'},
      {src: 'plugins/vueeditor.js', mode: 'client'},
  ],
  buildModules: [
    '@nuxtjs/dotenv',
    'nuxt-gsap-module'
  ],
  modules: [
    '@nuxtjs/axios',
    '@nuxtjs/auth',
    '@nuxtjs/device',
    ['vue-sweetalert2/nuxt',
      {
        confirmButtonColor: '#29BF12',
        cancelButtonColor: '#FF3333'
      }
    ],
    'cookie-universal-nuxt',
    '@nuxtjs/gtm',
    '@nuxtjs/google-gtag',
    'nuxt-user-agent',
  ],

  gtm: {
    id: process.env.GOOGLE_TAGS_ID,
    debug: false
  },
  'google-gtag': {
    id: process.env.GOOGLE_ANALYTICS_ID,
    debug: false
  },
  gsap: {
    extraPlugins: {
      cssRule: false,
      draggable: false,
      easel: false,
      motionPath: false,
      pixi: false,
      text: false,
      scrollTo: false,
      scrollTrigger: false
    },
    extraEases: {
      expoScaleEase: false,
      roughEase: false,
      slowMo: true,
    }
  },
  axios: {
    baseURL: process.env.BASE_URL,
  },
  auth: {
      strategies: {
        local: {
          endpoints: {
            login: { url: 'auth/login', method: 'post', propertyName: 'token' },
            logout: { url: 'auth/logout', method: 'post' },
            user: { url: 'auth/info', method: 'get', propertyName: '' }
          }
        }
      },
      redirect: {
        login: '/login',
        home: '',
        logout: '/login'
      },
      cookie: {
        prefix: 'auth.',
        options: {
          path: '/',
          maxAge: process.env.AUTH_COOKIE_MAX_AGE
        }
      }
  },

  publicRuntimeConfig: {
    gtm: {
      id: process.env.GOOGLE_TAGS_ID
    },
    'google-gtag': {
      id: process.env.GOOGLE_ANALYTICS_ID,
    }
  },
  build: {
    transpile: ['vee-validate/dist/rules'],
    plugins: [
      new webpack.ProvidePlugin({
        '$': 'jquery',
        jQuery: "jquery",
        "window.jQuery": "jquery",
        '_': 'lodash'
      }),
      new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/)
    ],
    postcss: {
      preset: {
        features: {
          customProperties: false,
        },
      },
    },
    loaders: {
      scss: {
        prependData: `$theme_colors: ("theme_body_color":"${process.env.THEME_BODY_COLOR}","theme_main_color":"${process.env.THEME_MAIN_COLOR}","theme_main_color2":"${process.env.THEME_MAIN_COLOR2}","theme_side_color":"${process.env.THEME_SIDE_COLOR}","theme_side_color2":"${process.env.THEME_SIDE_COLOR2}","theme_link_color":"${process.env.THEME_LINK_COLOR}");`
      }
    },
  }
}


我认为是时候分享我的理解了(尽管很少):

#1 as vue-router使用预取可能会占用大量内存,具体取决于链接数量。就我而言,没有太多,所以我就让它们去吧,还有一个选项可以在 nuxt 中禁用预取,所以如果您的应用程序非常繁忙或者您在单个页面中有数百个链接,最好禁用预取:

// locally
<nuxt-link to="/" no-prefetch>link</nuxt-link>

// globally in nuxt.config.js
router: {
  prefetchLinks: false
}

#2 我没有发现动态组件有任何问题

#3 不与$nuxt.$on但我在使用时经历过(事件监听器没有被删除)window.addEventListener in created钩。因此最好将所有侦听器尽可能移至客户端(在安装之前或安装之前)

#4 正如我在上面的评论中提到的,我尽可能多地删除了全局插件/css,以实现更轻量级的初始化并在本地使用它们,但是大约Vue.use()内存泄漏,那是我的误会! nuxt 文档中说:

不要使用 Vue.use()、Vue.component(),并且全局不要在该函数内插入 Vue 中的任何内容,专用于 Nuxt 注入。这会导致服务器端内存泄漏。

所以使用Vue.use() inside注入函数可能会导致内存泄漏Vue.use() itself.

至于其他的还没有答案

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Nuxt巨大内存使用/泄漏以及如何预防 的相关文章

随机推荐

  • 休眠 ID 生成器

    有人知道一些关于如何为 hibernate 创建自定义 ID 生成器的好教程吗 在 Google 上粗略搜索 hibernate 自定义 id 生成器教程 发现了以下可能性 我排除了那些看起来没有用的内容 并总结了每个内容的内容 http
  • 将标签添加到反应选择

    I am new to the react js here what I am trying to do is that 现在我尝试过的是 const options value chocolate label Chocolate valu
  • 我正在尝试使用 Stripe 和 NextJS 13.2.3 设置 webhook

    我能够通过内置 Stripe 页面成功结帐我的购物车 并且我会被重定向到我的 successUrl 路线 我的本地测试 webhook 正在按预期被调用 但是 当我包含代码来验证请求是否来自 Stripe 时 我收到一些错误 这是我在 Ne
  • COLLADA:反向绑定姿势在错误的空间?

    我正在编写自己的 COLLADA 导入器 我已经走了很远 加载了网格和材料等 但我在动画方面遇到了障碍 特别是 关节旋转 我用于对网格体进行蒙皮的公式很简单 weighted for i 0 i lt joint influences i
  • iPhone 的 /Documents 目录更改的通知

    我们有一个使用文件共享的应用程序 UIFileSharingEnable 已设置等 一切似乎都工作正常 但我正在寻找某种通知 说明何时在 iPhone 端添加 删除文件 有人可以建议吗 提前干杯 这个线程 https devforums a
  • len() 函数的成本

    费用是多少len https docs python org 2 library functions html lenPython 内置函数 列表 元组 字符串 字典 It s O 1 恒定时间 不取决于元素的实际长度 非常快 您提到的每种
  • 如何在 Firebase 托管上设置私有环境变量?

    由于 Divshot 最近关闭 我已将许多应用程序切换到 Firebase 托管 其中一些应用程序连接到外部 API 因此我需要一种在 Firebase 托管上存储私有环境变量 例如 用于 S3 访问的密钥 的方法 有人有什么想法吗 有这样
  • 如何从命令行调用多个文件到您的应用程序中?

    我正在向 Windows 注册表添加一个上下文菜单项 这样当我单击一个文件时 我可以调用我的应用程序 并将该文件作为参数设置到我的应用程序中 但是我如何才能将多个文件发送到我的应用程序 我选择的所有文件 现在我的命令是 C test dll
  • 解决方案无法在 Visual Studio 中运行/构建/重建

    当尝试在 Visual Studio 中对解决方案运行 生成 重建 时 没有任何反应 我可以使用 MSbuild exe 从命令提示符运行构建 这给了我期望的输出 构建成功 但是当尝试从 Visual Studio 运行它时 没有任何反应
  • geom_boxplot:将 alpha 水平映射到晶须和异常值

    有没有办法制作geom boxplot线条 胡须和离群点继承相同的alpha分配给箱线图fill在下面的情节中 library ggplot2 ggplot iris aes x Species y Sepal Length alpha S
  • C++ 结构模板特化

    我正在尝试开发自己的 3D 渲染器 为此我需要一个 3D 矢量结构 我试图使其尽可能通用 因此我使用模板化结构 我创建了一个Vec
  • 是否可以设置一个 IntelliJ Android 项目来与 Maven 一起使用?

    我想在 IntelliJ Android 项目中使用 Maven 依赖项 有人成功做到这一点吗 我在 Ubuntu 11 10 和 Mac OS X 10 7 3 上使用 IntelliJ IDEA 当前 v11 0 2 内部版本 111
  • 帕塞瓦尔定理对于正弦曲线 + 噪声的 FFT 不成立?

    预先感谢您对此主题的任何帮助 我最近一直在尝试计算包含噪声时离散傅立叶变换的帕塞瓦尔定理 我的代码来自这段代码 https stackoverflow com questions 30073508 parsevals theorem doe
  • 什么可能导致“BEGIN”语句“事务空闲”

    我们有一个 Node js 应用程序 它通过 pg promise 连接到 Postgres 11 服务器 所有进程都在 Docker 容器中的单个云服务器上运行 有时我们会遇到应用程序不再做出反应的情况 The last time thi
  • 在 中嵌入 Angular 指令

    我正在尝试获取一个在 a 内重复的角度指令 tr 如果没有该指令 代码是 tr td style display flex width 40 min width 300px span cluster Name span span clust
  • 从 React 组件进行 REST 调用

    我正在尝试从 React 组件进行 REST 调用并将返回的 JSON 数据渲染到 DOM 中 这是我的组件 import React from react export default class ItemLister extends R
  • 如何将文件添加到主包的 /Library/Sounds 目录?

    根据苹果的文档 https developer apple com library mac documentation Cocoa Conceptual Sound Tasks LoadingAudioData html 当尝试播放声音时
  • 如何处理 TransactionInDoubtException

    我有一些简单的SELECT声明和INSERT包裹在一个using TransactionScope 堵塞 更新 隔离级别为 ReadCommited我在调用时遇到以下异常scope Complete 见下文 与此同时 数据库完全处于另一个应
  • SpringMVC - 调度程序服务器的 url 模式样式

    我正在尝试构建一个宁静风格的 API 使用springMVC 当配置 springMVC 的 url pattern 时DispatcherServlet 似乎有2个选择 我需要一些建议 选择A 配置模式为
  • Nuxt巨大内存使用/泄漏以及如何预防

    我使用的是 Nuxt v2 13 和 Vuetify v2 也在我的默认布局中使用 keep alive 随着我的应用程序变得越来越大 我越来越注意到内存问题 因此我的应用程序需要在云服务器上至少大约 4GB RAM 才能构建并正常工作 我