如何解决Nuxt 巨大的内存使用/泄漏以及如何防止
我在 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 - 动态组件加载:
由于我的应用程序是双向的并且可以通过 .env
文件进行自定义,因此我不得不像这样有条件地动态延迟加载我的许多组件:
<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
钩子中将它们全部删除:
<script>
export default{
created:{
this.$nuxt.$on('myevent',()=>{
// do something
}
},beforeDestroy(){
this.$nuxt.$off('myevent')
}
}
</script>
但有人告诉我 created
挂钩上的侦听器将是 SSR,不会在 CSR beforeDestroy
挂钩中删除。所以我该怎么做?将 if(process.client){}
添加到 created
??
# 4 - 全局插件:
我找到了 this issue 和 this doc 。如 this question 中所述,我全局添加了我的插件/包。那么 vue.use()
是一个问题吗?我应该改用 inject
吗?怎么样?
// vue-product-zoomer package
import Vue from 'vue'
import ProductZoomer from 'vue-product-zoomer'
Vue.use(ProductZoomer)
# 5 - Vee 验证泄漏: 我读过here,这真的会导致泄漏吗?我正在使用 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 - setTimeout : 有没有必要用clearTimeout来做数据清理??
# 8 - 删除插件/包: 在this Doc中提到有些插件/包即使在组件被销毁后也不会被删除,我如何找到这些??
这是我的包和 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',{ rel: 'canonical',href: process.env.SITE_REL_CANONICAL },// { rel: 'stylesheet',href: 'https://cdn.jsdelivr.net/npm/font-awesome@4.x/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/vue-slick-carousel.js',{src: 'plugins/vuepersiandatepicker.js',mode: 'client'},{src: 'plugins/cropper.js',{src: 'plugins/vue-product-zoomer.js',{src: 'plugins/vueeditor.js',],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,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}");`
}
},}
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。