【发布时间】:2022-11-28 12:47:45
【问题描述】:
我有一个托管在 S3 存储桶上的 Nuxtjs 网站,它有多个路由/页面。我创建的这条特别的新路线正在投掷“无法在“节点”上执行“appendChild”:此节点类型不支持此方法。“(检查下面的 SS)
它不会在本地机器上发生,也不会抛出任何错误。显然,当我部署到 prod 时,应用程序会抛出如下 SS 所示的错误,但无法调试它,因为代码在构建时被缩小和丑化了。
奇怪的是,当我通过点击<NuxtLink>访问这条特定路线时,它工作正常,但如果我直接访问路线或者如果我点击<NuxtLink>并到达那里并重新加载页面,只有这样这个问题是不是来了。
您可以按照以下步骤重现此内容:
- 访问https://stackinvest.in
- 从导航栏点击“stack prime”,这将指向https://stackinvest.in/prime-mutual-funds
- 进入堆栈主页面后,重新加载页面。您将看到错误。
直接访问https://stackinvest.in/prime-mutual-funds路由也会看到这个错误。
问题是还有其他路线,正如您在 [主页] 的 Navbar 上看到的那样。如果我按照上述步骤操作,它们都工作正常。 (https://www.stackinvest.in/)
我有一个默认布局文件(由 Nuxt CLI 本身创建)
layouts/default.vue。代码如下所示:<template> <div ref="layout"> <app-navbar :isMobile="isMobile" @getstack="showModal = true"/> <nuxt /> <app-download v-if="showModal" :is-mobile="isMobile" @close="showModal=false"></app-download> </div> </template> <script> import Navbar from '../components/Navbar'; import Download from '../components/Download'; export default { name: 'Navbar', components: { appNavbar: Navbar, appDownload: Download }, data() { return { showModal: false, size: Number }; }, computed: { isMobile() { return this.size < 768; } }, mounted() { this.size = this.$refs.layout.clientWidth; } }; </script>代码
components/Navbar.vue。它不包含.removeEventListener()的任何代码。我确实尝试在<app-navbar>周围添加<client-only></client-only>包装标签 标签。什么都没用!<template> <nav class="nav-bar"> <div class="d-flex justify-content-center px-0 px-sm-128"> <div v-if="!isMobile" class="nav-bar-wrapper py-sm-4"> <div class="brand-logo"> <NuxtLink to="/"> <img alt="Stack Finance logo" data-not-lazy height="35px" src="https://webstatic.stackfinance.co/website/Group 73740.svg" > </NuxtLink> </div> <div class="d-flex justify-content-center"> <div class="nav-links w-100 mr-sm-4"> <div class="nav-links-item"> <NuxtLink class="fo-link" to="/prime-mutual-funds"> stack prime <div class="designer-line"></div> </NuxtLink> </div> <div class="nav-links-item"> <NuxtLink class="fo-link gt-nav-faq" to="/faq"> faq <div class="designer-line"></div> </NuxtLink> </div> <div class="nav-links-item"> <NuxtLink class="fo-link gt-nav-blog" to="/blogs"> blog <div class="designer-line"></div> </NuxtLink> </div> </div> <button id="nav-cta" ref="navCta" class="app-btn--sm" @click="focusSection">download stack</button> </div> </div> <div v-else class="nav-bar-wrapper--mob p-3"> <div class="brand-logo"> <NuxtLink to="/"> <img alt="Stack Finance logo" data-not-lazy height="22px" src="https://webstatic.stackfinance.co/website/Group 73740.svg" > </NuxtLink> </div> <div class="nav-links--collapsed"> <div class="menu-icon"> <input id="toggle" type="checkbox" @change="toggleMenu"> <label for="toggle"></label> </div> </div> <div v-if="showMenu" class="menu-container"> <div class="nav-links-item"> <NuxtLink class="fo-link" to="/prime-mutual-funds">stack prime</NuxtLink> </div> <div class="nav-links-item gt-nav-faq"> <NuxtLink class="fo-link" to="/faq">faq</NuxtLink> </div> <div class="nav-links-item"> <NuxtLink class="fo-link gt-nav-blog" to="/blogs">blog</NuxtLink> </div> </div> </div> </div> </nav> </template> <script> export default { name: 'Navbar', props: { isMobile: Boolean }, data() { return { showMenu: false }; }, methods: { focusSection() { this.$emit('getstack'); }, toggleMenu() { this.showMenu = !this.showMenu; } } }; </script> <style lang="scss"> ... </style>包.json
{ "name": "stack-web", "version": "4.0.0", "description": "", "author": "XYZ, "private": true, "scripts": { "dev:staging": "gulp set --env=staging && nuxt", "dev:prod": "gulp set --env=prod && nuxt", "build:staging": "gulp set --env=staging && nuxt build", "build:prod": "gulp set --env=prod && nuxt build", "start": "nuxt start", "generate": "nuxt generate", "lint": "eslint --ext .js,.vue --ignore-path .gitignore ." }, "dependencies": { "@nuxtjs/axios": "^5.9.5", "@nuxtjs/dayjs": "^1.4.0", "@nuxtjs/dotenv": "^1.4.1", "@nuxtjs/gtm": "^2.4.0", "@nuxtjs/robots": "^2.5.0", "@nuxtjs/sitemap": "^2.4.0", "@tryghost/content-api": "^1.11.0", "bootstrap-vue": "^2.2.2", "glob-all": "^3.1.0", "nuxt": "^2.0.0", "nuxt-helmet": "^1.2.3", "nuxt-lazy-load": "^1.2.9", "purgecss-webpack-plugin": "^2.0.5", "tinyurl": "^1.1.7", "vue": "^2.7.14", "vue-gtag": "^1.16.1", "vue-loader": "^15.10.0", "vue-slick-carousel": "^1.0.6", "vue-social-sharing": "^3.0.9", "vuelidate": "^0.7.7" }, "devDependencies": { "@nuxt/types": "^2.15.7", "@nuxtjs/eslint-config": "^1.0.1", "@nuxtjs/eslint-module": "^1.0.0", "@nuxtjs/stylelint-module": "^3.1.0", "babel-eslint": "^10.0.1", "eslint": "^6.1.0", "eslint-plugin-nuxt": ">=0.4.2", "gulp": "^4.0.2", "gulp-clean": "^0.4.0", "gulp-rename": "^2.0.0", "nuxt-compress": "^5.0.0", "sass": "^1.56.1", "sass-loader": "^10.1.1", "stylelint": "^10.1.0", "yargs": "^15.1.0" } }nuxt.config.js
/* eslint-disable dot-notation */ // import path from 'path'; // // import PurgecssPlugin from 'purgecss-webpack-plugin'; // import glob from 'glob-all'; // import shrinkRay from 'shrink-ray-current'; require('dotenv').config(); const keywords = `keywords`; export default { mode: 'universal', server: { port: process.env.PORT || 5100, host: '0.0.0.0' // default: localhost }, // render: { // compressor: shrinkRay() // }, router: { scrollBehavior() { let s; if (process.client) { s = { x: 0, y: 0 }; } return s; } }, /* ** Headers of the page */ head: { ... }, /* ** Customize the progress-bar color */ loading: { color: '#fff' }, /* ** Global CSS */ css: [ '@/assets/scss/app.scss' ], /* ** Plugins to load before mounting the App */ plugins: [ { src: '~/plugins/Vuelidate' }, { src: '~/plugins/hotjar', mode: 'client' }, { src: '~/plugins/gtag', mode: 'client' }, { src: '~/utils', mode: 'client' }, { src: '~/plugins/directives.js' } ], /* ** Nuxt.js dev-modules */ buildModules: [ 'nuxt-compress' // // Doc: https://github.com/nuxt-community/eslint-module // '@nuxtjs/eslint-module', // // Doc: https://github.com/nuxt-community/stylelint-module // '@nuxtjs/stylelint-module' ], /* ** Nuxt.js modules */ modules: [ 'bootstrap-vue/nuxt', '@nuxtjs/axios', '@nuxtjs/dotenv', '@nuxtjs/gtm', 'nuxt-lazy-load', 'nuxt-helmet', '@nuxtjs/robots', '@nuxtjs/sitemap', 'vue-social-sharing/nuxt', '@nuxtjs/dayjs' ], robots: { ... }, sitemap: { ... }, gtm: { id: '<KEY>', pageTracking: true, pageViewEventName: 'nuxtRoute' }, dayjs: { locales: ['en'], defaultLocale: 'en', plugins: [ 'utc' // import 'dayjs/plugin/utc' ] }, module: { rules: [ { test: /\.s[ac]ss$/i, use: ['style-loader', 'css-loader', 'sass-loader'] } ] }, bootstrapVue: { bootstrapCSS: false, bootstrapVueCSS: false }, /* ** Build configuration */ build: { /* ** You can extend webpack config here */ extractCSS: true, extend(config, { isDev, isClient }) { if (isDev && isClient) { config.devtool = 'source-map'; config.plugins.push( // new PurgecssPlugin({ // paths: glob.sync([ // path.join(__dirname, './pages/**/*.vue'), // path.join(__dirname, './layouts/**/*.vue'), // path.join(__dirname, './components/**/*.vue') // ]), // whitelist: ['html', 'body'] // }) ); } } } };prime-mutual-funds.vue 的代码
<template> <main ref="page" class="prime-main"> <section class="hero"> ... </section> <section class="risk-analysis"> <div class="row"> <div v-if="!isMobile" class="col-sm"> ... </div> <div class="col-sm d-flex align-items-center mb-4 mb-sm-0"> <div> <a v-if="isMobile" class="text-color text-decoration-done fw-600" :href="getOS() === 'android' ? 'URL1': 'url2'"> </a> <a v-else class="text-color text-decoration-done fw-600" @click="showModal = true" href="javascript:void(0)"> ... </a> </div> </div> <div v-if="isMobile" class="col-sm"> ... </div> </div> </section> <section class="prime-detail"> <div class="prime-detail-header"> <h2 class="section-heading">Lorem Lorem</h2> <div class="d-flex mt-3 mt-sm-4"> <a href="#options" class="prime-detail-tab" @click="activeTabIndex = 0" :class="{'active': activeTabIndex === 0}">investment options</a> <a href="#automate" class="prime-detail-tab" @click="activeTabIndex = 1" :class="{'active': activeTabIndex === 1}">automated investing</a> <a href="#track" class="prime-detail-tab" @click="activeTabIndex = 2" :class="{'active': activeTabIndex === 2}">actionable insights from experts</a> </div> </div> <section id="options" class="p-4" v-if="isMobile"> ... </section> <section v-else class="scroller pb-sm-128"> <div class="scroller-left"> <div id="options" class="scrollable-element"> <div id="1" class="mxw-600" v-intersection="{threshold: .7, cb: updateRightContainer}"> ... </div> </div> <div class="scrollable-element"> <div id="2" class="mxw-600" v-intersection="{threshold: .7, cb: updateRightContainer}"> ... </div> </div> <div id="automate" class="scrollable-element"> <div id="3" class="mxw-600" v-intersection="{threshold: .7, cb: updateRightContainer}"> ... </div> </div> <div class="scrollable-element"> <div id="4" class="mxw-600" v-intersection="{threshold: .7, cb: updateRightContainer}"> ... </div> </div> <div class="scrollable-element"> <div id="5" class="mxw-600" v-intersection="{threshold: .7, cb: updateRightContainer}"> ... </div> </div> <div id="track" class="scrollable-element"> <div id="6" class="mxw-600" v-intersection="{threshold: .7, cb: updateRightContainer}"> ... </div> </div> <div class="scrollable-element"> <div id="7" class="mxw-600" v-intersection="{threshold: .7, cb: updateRightContainer}"> ... </div> </div> </div> <div class="scroller-right"> <div class="sticky-content"> <div class="sticky-content-box" v-if="activateText"> <span class="sticky-content-tag" :style="{backgroundColor: contentIndex[activeContentIndex].bgc}">{{ contentIndex[activeContentIndex].tag }}</span> <h3 class="sticky-content-title mt-4"> {{ contentIndex[activeContentIndex].title }} </h3> </div> <img v-else height="520px" ref="info" alt="info-img" src="https://webstatic.stackfinance.co/website/goals.webp"/> </div> </div> </section> </section> <section class="rewards"> <h3 v-if="isMobile" class="rewards-heading">good financial habits <br> deserve <span class="text-white">great</span> rewards</h3> <h3 v-else class="rewards-heading">good financial habits deserve <br> <span class="text-white">great</span> rewards</h3> <h5 class="rewards-subheading">choose a free US stock with every investment.</h5> <a :href="getOS() === 'android' ? '<url1>': '<url1>'" v-if="isMobile" class="app-btn--sm d-block bgi-none bg-white text-color mx-auto my-4" style="width: 190px;"> download stack </a> <button v-else class="app-btn--white mt-sm-4" @click="showModal = true">download stack</button> </section> <app-grow-wealth :is-mobile="isMobile" @download="showModal = true"></app-grow-wealth> <app-footer :is-mobile="isMobile"></app-footer> <div v-if="isMobile" class="store-container py-2 px-4 bg-white position-fixed"> <a href="https://stack.app.link/3yAcChs5emb" rel="noopener"> <img height="40px" src="https://webstatic.stackfinance.co/website/playstore.png" alt="playstore"> </a> <a href="https://stack.app.link/10JkMU6Xemb" rel="noopener"> <img class="float-right" height="40px" src="https://webstatic.stackfinance.co/website/appstore.png" alt="appstore"> </a> </div> <div v-if="showFaq" class="pop-box"> <app-faq-section :squeeze="true"></app-faq-section> </div> <button id="popover-button-sync" class="floating-help" @click="showFaq = !showFaq"> <img height="40px" src="https://webstatic.stackfinance.co/website/Chat 4_2x.png" alt="messenger"> </button> <app-download v-if="showModal" :is-mobile="isMobile" @close="showModal=false"></app-download> </main> </template> <script> import Footer from '../components/Footer'; import FaqSection from '../components/Faq-Section'; import Download from '../components/Download'; import { fetchOS } from '../utils'; import GrowWealth from '../components/GrowWealth'; export default { name: 'PrimeMutualFunds', components: { appFooter: Footer, appFaqSection: FaqSection, appDownload: Download, appGrowWealth: GrowWealth }, data() { return { size: Number, showModal: false, showFaq: false, activateText: false, activeTabIndex: 0, imgIndex: { 1: 'URL', 2: 'URL', 6: 'URL', 7: 'URL' }, contentIndex: { 3: { tag: '...', bgc: '#f9f2ea', title: '...' }, 4: { tag: '...', bgc: '#e1f4f0', title: '...' }, 5: { tag: 'investment reminder', bgc: '#ccebff', title: '...' } }, activeContentIndex: 3 }; }, computed: { isMobile() { return this.size < 768; } }, mounted() { this.size = this.$refs.page.clientWidth; }, methods: { getOS: () => fetchOS(), updateRightContainer({ isIntersecting, target }) { if (isIntersecting) { const x = target.getAttribute('id'); this.activeTabIndex = 0; const ids = [3, 4, 5]; if (ids.includes(+x)) { this.activateText = true; this.activeContentIndex = x; this.activeTabIndex = 1; return; } if ([6, 7].includes(+x)) { this.activeTabIndex = 2; } this.activateText = false; if (this.$refs.info) { this.$refs.info.setAttribute('src', this.imgIndex[x]); } } } } }; </script> <style lang="scss" scoped> ... </style>direction.js代码
Vue.directive('intersection', { bind(el, binding) { const threshold = binding.value.threshold || 0; const defaultCb = () => { console.log('No callback passed'); }; const cb = binding.value.cb || defaultCb; if (isNaN(threshold)) { return; } const observer = new IntersectionObserver((entries) => { entries.forEach((elem) => { cb(elem); }); }, { threshold }); observer.observe(el); } }); Vue.directive('scroll', { inserted(el, binding) { const f = function(evt) { if (binding.value(evt, el)) { window.removeEventListener('scroll', f); } }; window.addEventListener('scroll', f); } });如果我注释掉导航栏并部署,重新加载工作正常,这个 URL 没有任何问题-https://stackinvest.in/prime-mutual-funds
【问题讨论】:
-
正如你所说
Once you're on stack prime page, reload the page. You will see the error为什么它在reload上询问Changes that you made may not be saved.? -
您的代码可能不是同构的。一些解决方案是described here。在您的情况下,如果我们想更进一步,我们将需要您的
package.json+nuxt.config.js文件。此外,通过在本地构建(和预览)来调试它,您应该会遇到同样的问题。无需在生产中调试它。 -
您可能还有一些中间件或全局插件。你有公共的 github 仓库吗?
-
嗨@kissu,我已经添加了这两个文件。问题是没有控制台日志错误,并且在本地终端中。我确实有插件,但这也会影响其他路线。为什么只是这条特定的路线。
-
可以添加
prime-mutual-funds页面的代码吗?
标签: javascript vue.js nuxt.js