Using NextJS: How to remove a script when the website URL includes the parameter ?unload-script

When using webdriver to test our website, an Intercom widget becomes embedded in the screenshot as the webdriver scrolls down. Attempts to hide Intercom via CSS have resulted in a javascript error:

Cannot read properties of null (reading 'style').

It's worth noting that Intercom is loaded through Segment.

The loading mechanism involves NextJS, with the following snippet found in /pages/document.tsx:

<script
    type="text/partytown" dangerouslySetInnerHTML={{ __html: `!function(){var analytics=window.analytics=window.analytics||[];if(!analytics.initialize)if(analytics.invoked)window.console&&console.error&&console.error("Segment snippet included twice.");else{analytics.invoked=!0;analytics.methods=["trackSubmit","trackClick","trackLink","trackForm","pageview","identify","reset","group","track","ready","alias","debug","page","once","off","on","addSourceMiddleware","addIntegrationMiddleware","setAnonymousId","addDestinationMiddleware"];analytics.factory=function(e){return function(){var t=Array.prototype.slice.call(arguments);t.unshift(e);analytics.push(t);return analytics}};for(var e=0;e<analytics.methods.length;e++){var key=analytics.methods[e];analytics[key]=analytics.factory(key)}analytics.load=function(key,e){var t=document.createElement("script");t.type="text/javascript";t.async=!0;t.src="https://cdn.segment.com/analytics.js/v1/" + key + "/analytics.min.js";var n=document.getElementsByTagName("script")[0];n.parentNode.insertBefore(t,n);analytics._loadOptions=e};analytics._writeKey="xxxxx";;analytics.SNIPPET_VERSION="4.15.3";analytics.load("xxxx");analytics.page();}}();` }} />

If there is a need to inform NextJS to unload the Segment script when webdriver loads a URL containing certain parameters (e.g. www.example.com?no-segment), how can this be achieved?

UPDATE: The content of /pages/_document.tsx has been revised as follows:

import { Partytown } from '@builder.io/partytown/react';
import { Head, Html, Main, NextScript } from 'next/document'
import { ServerStyleSheetDocument } from 'next-sanity/studio'
import { useRouter } from 'next/router'
import { useState, useEffect } from 'react'
 
const router = useRouter();
const [isUnloadSegment, setIsUnloadSegment] = useState(false);

useEffect(() => {
  if (router.query['no-segment'] !== undefined) {
    setIsUnloadSegment(true);
  }
}, [router.query]);

export default class Document extends ServerStyleSheetDocument { 
  render() {   
    return (
      <Html lang="en">
        <Head>
          <Partytown debug={false} forward={['dataLayer.push']} />
          <style dangerouslySetInnerHTML={{
            __html: `@font-face {font-family: 'Poppins';src: url('/fonts/Poppins-Regular.woff2') format('woff2');font-weight: normal;font-style: normal;font-display: swap;}@font-face {font-family: 'Poppins';src: url('/fonts/Poppins-Medium.woff2') format('woff2');font-weight: 500;font-style: normal;font-display: swap;}@font-face {font-family: 'Poppins';src: url('/fonts/Poppins-SemiBold.woff2') format('woff2'),;font-weight: 600;font-style: normal;font-display: swap;}@font-face {font-family: 'Poppins';src: url('/fonts/Poppins-Italic.woff2') format('woff2');font-weight: normal;font-style: italic;font-display: swap;}`}} />
        </Head>
        <body>
          <Main />
          <NextScript />
          {!isUnloadSegment && (
          <script
              type="text/partytown" dangerouslySetInnerHTML={{ __html: `!function(){var analytics=window.analytics=window.analytics||[];if(!analytics.initialize)if(analytics.invoked)window.console&&console.error&&console.error("Segment snippet included twice.");else{analytics.invoked=!0;analytics.methods=["trackSubmit","trackClick","trackLink","trackForm","pageview","identify","reset","group","track","ready","alias","debug","page","once","off","on","addSourceMiddleware","addIntegrationMiddleware","setAnonymousId","addDestinationMiddleware"];analytics.factory=function(e){return function(){var t=Array.prototype.slice.call(arguments);t.unshift(e);analytics.push(t);return analytics}};for(var e=0;e<analytics.methods.length;e++){var key=analytics.methods[e];analytics[key]=analytics.factory(key)}analytics.load=function...
          )}
        </body>
      </Html>
    )
  }
}

Unfortunately, running the local site triggers an error message:

TypeError: Cannot read properties of null (reading 'useContext')

https://i.sstatic.net/Ka9gx.png

Answer №1

If you're facing a similar issue, I have a solution that might help. Give it a try and see if it works for you!

To start with, you can extract the "no-segment" availability from the Router URL and save it in your state. This will allow you to use it later to set conditions like this:

const router = useRouter();
const [isUnloadSegment, setIsUnloadSegment] = useState(false);

useEffect(() => {
  if (router.query['no-segment'] !== undefined) {
    setIsUnloadSegment(true);
  }
}, [router.query]);

Once you've done that, you can implement the condition as per your requirement. Since you mentioned that your script is located in /pages/document.tsx, here's how you can structure it:

{!isUnloadSegment && (
  <script
    type="text/partytown" dangerouslySetInnerHTML={{ __html: `!function(){var analytics=window.analytics=window.analytics||[];if(!analytics.initialize)if(analytics.invoked)window.console&&console.error&&console.error("Segment snippet included twice.");else{analytics.invoked=!0;analytics.methods=["trackSubmit","trackClick","trackLink","trackForm","pageview","identify","reset","group","track","ready","alias","debug","page","once","off","on","addSourceMiddleware","addIntegrationMiddleware","setAnonymousId","addDestinationMiddleware"];analytics.factory=function(e){return function(){var t=Array.prototype.slice.call(arguments);t.unshift(e);analytics.push(t);return analytics}};for(var e=0;e<analytics.methods.length;e++){var key=analytics.methods[e];analytics[key]=analytics.factory(key)}analytics.load=function(key,e){var t=document.createElement("script");t.type="text/javascript";t.async=!0;t.src="https://cdn.segment.com/analytics.js/v1/" + key + "/analytics.min.js";var n=document.getElementsByTagName("script")[0];n.parentNode.insertBefore(t,n);analytics._loadOptions=e};analytics._writeKey="xxxxx";;analytics.SNIPPET_VERSION="4.15.3";analytics.load("xxxx");analytics.page();}}();` }} />
)}

AN ADDED SECTION:

Now, let's consider implementing this logic in a class component.

import { Partytown } from '@builder.io/partytown/react';
import { Head, Html, Main, NextScript } from 'next/document';
import { ServerStyleSheetDocument } from 'next-sanity/studio';
import { useRouter } from 'next/router';
import { useState, useEffect } from 'react';

class Document extends ServerStyleSheetDocument {
  constructor(props) {
    super(props);

    this.state = {
      isUnloadSegment: false,
    };
  }

  componentDidMount() {
    const { query } = useRouter();
    if (query['no-segment'] !== undefined) {
      this.setState({ isUnloadSegment: true });
    }
  }

  render() {
    const { isUnloadSegment } = this.state;

    return (
      <Html lang="en">
        <Head>
          <Partytown debug={false} forward={['dataLayer.push']} />
          <style
            dangerouslySetInnerHTML={{
              __html: `@font-face {font-family: 'Poppins';src: url('/fonts/Poppins-Regular.woff2') format('woff2');font-weight: normal;font-style: normal;font-display: swap;}@font-face {font-family: 'Poppins';src: url('/fonts/Poppins-Medium.woff2') format('woff2');font-weight: 500;font-style: normal;font-display: swap;}@font-face {font-family: 'Poppins';src: url('/fonts/Poppins-SemiBold.woff2') format('woff2'),;font-weight: 600;font-style: normal;font-display: swap;}@font-face {font-family: 'Poppins';src: url('/fonts/Poppins-Italic.woff2') format('woff2');font-weight: normal;font-style: italic;font-display: swap;}`,
            }}
          />
        </Head>
        <body>
          <Main />
          <NextScript />
          {!isUnloadSegment && (
            <script
              type="text/partytown"
              dangerouslySetInnerHTML={{
                __html: `!function(){var analytics=window.analytics=window.analytics||[];if(!analytics.initialize)if(analytics.invoked)window.console&&console.error&&console.error("Segment snippet included twice.");else{analytics.invoked=!0;analytics.methods=["trackSubmit","trackClick","trackLink","trackForm","pageview","identify","reset","group","track","ready","alias","debug","page","once","off","on","addSourceMiddleware","addIntegrationMiddleware","setAnonymousId","addDestinationMiddleware"];analytics.factory=function(e){return function(){var t=Array.prototype.slice.call(arguments);t.unshift(e);analytics.push(t);return analytics}};for(var e=0;e<analytics.methods.length;e++){var key=analytics.methods[e];analytics[key]=analytics.factory(key)}analytics.load=function(key,e){var t=document.createElement("script");t.type="text/javascript";t.async=!0;t.src="https://cdn.segment.com/analytics.js/v1/" + key + "/analytics.min.js";var n=document.getElementsByTagName("script")[0];n.parentNode.insertBefore(t,n);analytics._loadOptions=e};analytics._writeKey="piQWMo5agM7Jcwm9g4sJA1rhBfZfeAB3";;analytics.SNIPPET_VERSION="4.15.3";analytics.load("piQWMo5agM7Jcwm9g4sJA1rhBfZfeAB3");analytics.page();}}();`,
              }}
            />
          )}
        </body>
      </Html>
    );
  }
}

export default Document;

Give this approach a try and hopefully it resolves the issue you are encountering.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Tips for blocking the insertion of "Emoji & Symbols" into an input field

Currently, I am utilizing Vue JS, but I am willing to consider vanilla JS suggestions as well since they both serve the same purpose. My objective is to block default emojis from being inserted into a text field through either the IOS keyboard or the (CMD ...

Adding data to a Vue.JS array from an HTML source

I'm facing a challenge with my assignment where I am struggling to input data from HTML into the VUE.JS array. I have created this form, and now I need assistance in updating the Students array in Vue.js when a user completes the form and clicks on th ...

What steps do I need to take to incorporate dialog-polyfill into my React application?

Incorporating Firebase and FirebaseUI in my React application for phone number registration has been successful on Google Chrome desktop. However, when testing it on different browsers, such as through , I encountered an issue with the country code selecto ...

Accents marked with diacritics are not being detected + An issue occurred while

I'm currently working on putting together a Spanish dictionary by sourcing the definitions from www.rae.es. However, there are a couple of challenges I'm facing: One issue is that the search engine does not function properly with acute accent ...

Steps for integrating a universal loader in Angular

My implementation of a global loader is as follows: In the CoreModule: router.events.pipe( filter(x => x instanceof NavigationStart) ).subscribe(() => loaderService.show()); router.events.pipe( filter(x => x instanceof NavigationEnd || x in ...

Do you think it's essential to utilize express for node in developing moderate-sized applications?

What is the best approach for handling cookies and authentication in a project with approximately 30 or 40 routes? Is it feasible to manage cookies and authentication without using Express? What percentage of developers prefer using Express over bare bon ...

Encountering a blank webpage displaying a warning that reads, "The use of 'event.returnValue' is outdated

Although this issue has been discussed before and was previously considered a bug, I am currently using jQuery v1.11.0, which should have resolved it. The problem I am encountering is that when my page loads, there is supposed to be a slide-in effect (as a ...

Angular offers the ability to configure HTTP headers for requests

I need to include a header named "access-token" in all of my http requests like this: var app= angular.module("MainModule", ["ngRoute"]); app.run(function($http){ $http.defaults.headers.common['access-token'] =ACCESSTOKEN; }) and in my ser ...

Troubleshooting a JavaScript bug involving a TYPO3 plugin and jQuery

Having some trouble with jQuery or javascript while using the "Easy route planner" extension in typo3. You can find the extension here: Initially, the jQuery of the extension wasn't functioning at all. It seemed to be a conflict with the $ variable. ...

Issue with handling .bind in Angular's karma/jasmine tests Angular's karma/j

When writing unit tests for my functions, I encountered an issue with a bound function in the test runner. The problem arose when trying to bind a function to have reference to 'this' inside an inner function. Here is the code snippet in question ...

Use the JavaScript executor to combine a dynamic string

I have a String variable that retrieves IDs from an Excel sheet. String id = formatter.formatCellValue(sheet.getRow(i).getCell(2)); I am trying to dynamically update the ID using JavaScript executor, but it seems that the concatenation is not working cor ...

Stop closing the bootstrap modal popup when the space key is pressed

Is there a way to prevent the model popup from closing when the space or enter key is pressed on the keyboard? I have already tried using data-backdrop="static" data-keyboard="false" but it still closes. Additionally, I have ensured that the form tag is no ...

Encountering an undefined json array when making an AJAX request

There have been numerous questions on this topic, but none of the specific solutions seemed to apply to my situation. So, I apologize if this is a duplicate query. I am currently working on fetching data from an SQL database using a PHP file that passes t ...

Troubleshooting Navigation Bar Toggle Button Issue in Bootstrap 5

Currently, I am in the process of working on a web project that requires the implementation of a responsive sidebar. This sidebar should be toggleable using a button located in the navigation bar. My choice for the layout is Bootstrap, and I have come acr ...

PhoneGap 3.5.0 FileTransfer onprogress issue unresolved

I can't seem to get the onprogress event handler to work when downloading a file. The success callback is triggered and the download goes through successfully, but for some reason, the progress events are not firing. Does anyone see any issues with my ...

What is the best way to terminate a file upload initiated by ajaxSubmit() in jQuery?

A snippet of code I currently have is: UploadWidget.prototype.setup_form_handling = function() { var _upload_widget = this; $('form#uploader') .unbind('trigger-submit-form') // Possibly a custom method by our company . ...

Preventing Next.js API from overwriting my ETag header: A guide

I'm a newcomer to Next.js and it seems like Next.js is interfering with my ETag header. I need to customize the ETag as I integrate my server with S3 and want to utilize the S3 Object's Etag for cache control. To test this, in the code snippet b ...

It appears that using "object[prop]" as a name attribute does not function properly in HTML

After using console.log on the req.body I received this output: [Object: null prototype] { 'shoe[name]': 'Shoe Name', 'shoe[description]': '', 'shoe[pictures]': '', 'shoe[collections] ...

Tips for crafting interactive Dropdown menus

Visit this link for more information Hello all, I am a beginner in HTML and Javascript and seeking guidance on how to create dynamic dropdown menus similar to the ones on the provided website. I have successfully implemented the source code, but my questi ...

Sidebar-driven top navigation menu

I am currently developing a Single Page Application using VueJS along with vuerouter. In my App.vue file, the structure is as follows: <template> <div id="app"> <header><topbar></topbar></header> <div cl ...