2

I have a Nuxtjs website hosted on S3 bucket, it has multiple routes/pages. This one particular new route that I have created is throwing "Failed to execute 'appendChild' on 'Node':This node type does not support this method." (check SS below)

enter image description here

It is not happening on local machine and not throwing any error. Apparently, when I deploy to prod, it the app is throwing error as below SS, but cannot debug it as the code is minified and uglified while building.

enter image description here

The weird part is, when I'm visiting this particular route by clicking on <NuxtLink> it is working fine, but if I'm direclty visiting route or if I click on <NuxtLink> and reach there and reload the page, only then is this issue is coming.

You can reproduce this by following below steps:

  1. Visit https://stackinvest.in
  2. From navbar click on "stack prime", that will lead to https://stackinvest.in/prime-mutual-funds
  3. Once you're on stack prime page, reload the page. You will see the error.

You can also see this error if you visit https://stackinvest.in/prime-mutual-funds route directly.

The problem is there are other routes too, as you can see on Navbar on [home page]. They all are working fine if I follow above steps. (https://www.stackinvest.in/)

I've a default layout file (created by Nuxt CLI itself) layouts/default.vue. Code is shown below:

<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>

Code components/Navbar.vue. It does not contain any code for .removeEventListener(). I did tried to add <client-only></client-only> wrapper tag around <app-navbar> tag. Nothing worked!

<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>

package.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

require('dotenv').config();

const keywords = `...`;

export default {
  ssr: true,
  scrollToTop: true,
  server: {
    port: process.env.PORT || 5100,
    host: '0.0.0.0' // default: localhost
  },
  router: {
    scrollBehavior() {
      return { x: 0, y: 0 };
    }
  },
  /*
   ** Headers of the page
   */
  head: {
    title: 'Stack: Modern Investment Management',
    meta: [ ... ]
  },

  loading: {
    color: '#fff'
  },
 
  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', mode: 'client' }
  ],
  /*
   ** Nuxt.js dev-modules
   */
  buildModules: [
    'nuxt-compress'
   
  ],
  /*
   ** 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: {
    UserAgent: '*',
    Disallow: ''
  },
  sitemap: {
    gzip: true,
    hostname: 'https://stackinvest.in/'
  },
  gtm: {
    id: 'GTM-NZW7782',
    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 }) {
      config.resolve.symlinks = false;
      if (isDev && isClient) {
        config.devtool = 'source-map';
        
      }
    }
  }
};

Code for 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> 
      <client-only><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></client-only>
    </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 code below
      if (!process.browser || !process.client) {
         return 'android';
      }

      const userAgent = navigator.userAgent || navigator.vendor || window.opera;

  if (/android/i.test(userAgent)) {
    return 'android';
  }

  if (/iPad|iPhone|iPod/.test(userAgent) && !window.MSStream) {
    return 'ios';
  }

  return 'unknown';
    },
    updateRightContainer({ isIntersecting, target }) {
      if (isIntersecting) {
        const x = target.getAttribute('id');
        this.activeTabIndex = 0;
        if ([5, 6, 7].includes(+x)) {
          this.activateText = true;
          this.activeContentIndex = x;
          this.activeTabIndex = 2;
          return;
        }

        if ([3, 4].includes(+x)) {
          this.activeTabIndex = 1;
        }

        this.activateText = false;
        if (this.$refs.info) {
          this.$refs.info.setAttribute('src', this.imgIndex[x]);
        }
      }
    }
    }
  }
};
</script>

Code of direction.js


Vue.directive('intersection', {
  bind(el, binding) {
    if (process.client) {

      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);
    }
  }
});

If I comment out the navbar and deploy, the reload works fine without any issue for this URL -https://stackinvest.in/prime-mutual-funds

Yashwardhan Pauranik
  • 5,370
  • 5
  • 42
  • 65
  • as you said `Once you're on stack prime page, reload the page. You will see the error` why is it asking `Changes that you made may not be saved.` on `reload`? – Ankit.Z Nov 25 '22 at 14:33
  • Your code is probably not isomorphic. Some solutions are [described here](https://stackoverflow.com/a/67751550/8816585). In your case, if we want to move further we will need your `package.json` + `nuxt.config.js` files. Also, debug it by building (and previewing) locally, you should have the same issue. No need to debug it on production. – kissu Nov 25 '22 at 14:47
  • You may also have some middlewares or global plugins. Do you have a public github repo? – kissu Nov 25 '22 at 14:48
  • Hi @kissu, I've added both files. Problem is there are no console logs errors and in the terminal on the local. I do have plugins, but that should affect other routes as well. Why just this particular route. – Yashwardhan Pauranik Nov 27 '22 at 09:46
  • 1
    Can you add the codes of `prime-mutual-funds` page? – Amini Nov 27 '22 at 13:31
  • @Amini I have added that with directive.js code as well, that page uses v-intersection directive as well. – Yashwardhan Pauranik Nov 28 '22 at 04:26
  • Few notes: `dotenv` is not used anymore by Nuxt (baked-in). `mode: 'universal'` is obsolete too. You probably want `ssr: true` + `target: 'static'`. The `process.client` inside of `router` looks not necessary. Did you tried to comment out `v-intersection`? Is it SSR-friendly? Are you sure your other components are safe? Tried to comment out some of them? What is `fetchOS` doing? `updateRightContainer` looks quite dangerous tbh. – kissu Dec 19 '22 at 05:48
  • @kissu Today I've tried most of the suggested notes you shared above. In a nutshell, - NOTHING WORKED. 1. `ssr: true` + `target: 'static'` - Broke the whole page where I'm using Ghost CMS APIs in `asyncData()`. Hence removed `target: 'static'` part. 2. `router` property updated in `nuxt.config.js` 3. I check a page - https://stackinvest.in/masterclass; I also started breaking now, here I do not even use `v-intersection` directive here. 4. `fetchOS` checks if user works on windows or apple devices. Updated the code above. – Yashwardhan Pauranik Dec 23 '22 at 08:30
  • 1
    It's hard to debug right here. It would be easier to upload your code on github so we could have a pull request. Otherwise, go to the route in development and check the console and you surely gonna see the error in console. – Amini Feb 09 '23 at 06:40
  • Hi @Amini it is a private repository. Cannot make it public. I can share a meet link if we can connect. – Yashwardhan Pauranik Feb 09 '23 at 07:20
  • Where could we connect? In order to help to fix this bug. – Amini Feb 10 '23 at 10:37
  • Here is my LinkedIn - https://www.linkedin.com/in/yashwardhan-pauranik-a4591ba8/ Kindly drop me a message – Yashwardhan Pauranik Feb 13 '23 at 10:45
  • @YashwardhanPauranik, I apologize that I didn't notice your comment. I followed you on linked but accidentally withdrew the connection request. LinkedIn: Amirreza Amini – Amini Feb 20 '23 at 09:34

2 Answers2

0

These are the possible ways to check:

  1. Check the console in development while you're changing the routes. You surely gonna see the related error there. I've experienced this.
  2. I checked the console and saw this related error. enter image description here Search for removeEventListener and see where you used it that somehow connects to the route prime-mutual-find and its components. It can affect the store, your directives, and your plugins. This also can happen because of you selecting an element and the element doesn't exist so you do a removeEventListener on it and so there is no elements, the error occurs. You can prevent this by,
if (element) {
  // element.removeEventListener(...)
}
  1. If there was no removeEventListener used in your project, it can be because of the npm packages you use and register them as plugins.
  2. I used the source tab in dev tools to check where the error happens and got a clue of file 983dbf9.js. Check this URL, and recognize the script where you have use these in your vue components.
Amini
  • 1,620
  • 1
  • 8
  • 26
  • 1. No errors there, already checked 2. I had already removed that code, so now no `removeEventListener` is there. 3. There is one directive, that I've already added and it does not contains `removeEventListener ` 4. Since the file is minified & uglified, cannot get a trace of it. Already tried – Yashwardhan Pauranik Feb 09 '23 at 07:28
  • It's not because your code is not iaomorphic. Same issue as here: https://stackoverflow.com/a/67978474/8816585 – kissu Feb 09 '23 at 07:37
-1

Intersection Observer and windows are client-side only code (cannot be used while within a Node.js context).
You cannot use them like you're doing right now because they are both running on client and server-side as of right now.

Please refer to this answer on ways to fix that (mainly run your code only while on client-side), as suggested in my first comment.

kissu
  • 40,416
  • 14
  • 65
  • 133
  • But intersection observer is used inside prime-mutual-funds.vue.. When I comment out Navbar.vue, then I cannot see any issue on production. Also, same is being used on index.vue as well, but there reload thing is working fine. – Yashwardhan Pauranik Nov 28 '22 at 05:37
  • @YashwardhanPauranik having it used as `client-side` only as suggested in my answer will not break your app, you will only run it on there and not on both server + client. Please careful read my answer. – kissu Nov 28 '22 at 08:25
  • I'm sorry, but your comment is not clear to me. Can you please rephrase? – Yashwardhan Pauranik Nov 28 '22 at 09:53
  • @YashwardhanPauranik you cannot use `browser` code on the `server`. IntersectionObserver and `window` are `browser` only. You need to run those only on client-side, so use [my answer](https://stackoverflow.com/a/67751550/8816585) to do that. – kissu Nov 28 '22 at 09:58
  • Tried whatever you have suggested. But some how it is just not working :( – Yashwardhan Pauranik Dec 19 '22 at 05:30
  • @YashwardhanPauranik you don't have more details? "it doesn't work" is quite hard to debug and move forward with. – kissu Dec 19 '22 at 05:31
  • I did some changes, where I have wrapper `section.scroller` div with ``. Also, I have replaced the `bind(el, binding)` func. with `mounted(el, binding)` inside the directive now. Still not results. Updating above code as well.. – Yashwardhan Pauranik Dec 19 '22 at 05:36