intergi / pw-react-component

Playwire's react component library
2 stars 1 forks source link

Support SSR render in Next.js #3

Open meotimdihia opened 1 year ago

meotimdihia commented 1 year ago

I get this error while importing ramp.

ReferenceError: window is not defined

And there is a bug on the Stackblitz: https://stackblitz.com/edit/next-typescript-pokptk-zkasxp?file=styles%2Fglobals.css,pages%2Findex.tsx

jarrettabello commented 1 year ago

Thanks for the heads up. We are just seeing the issues here in the repo and are working on a process to address incoming issues. As a development team we are used to processing issues that come through bug reports through our technical solutions team - so this is new to us!! Make sure to reach out to your technical solutions contact if you continue to have issues!

ColeTownsend commented 10 months ago

Had a similar issue here. for nextjs this is particularly tricky because you can support a number of types of rendering.

I came across this one about using Google Ads and found it helpfu @meotimdihia https://dev.to/shriekdj/how-to-add-google-ad-sense-nextjs-13-with-app-router-auto-ads-and-unit-ads-hfa

Did you get a solution?

meotimdihia commented 10 months ago

@ColeTownsend Adsense is different. I don't see this problem while using Adsense.

ColeTownsend commented 10 months ago

@meotimdihia were you able to figure out with just NextJS?

meotimdihia commented 10 months ago

@ColeTownsend If you mean Playwire then something like this, I stopped using Playwire 8 months ago => I don't sure it is still useful:

playwire_ramp.tsx

import { Ramp } from "pw-react-component"

export default function PlaywireRamp() {
  return <Ramp publisherId="1024601" id="73961" />
}

playwire_script.tsx

import dynamic from "next/dynamic"
const PlaywireRamp = dynamic(() => import("@components/ads/playwire_ramp"), {
  ssr: false
})
export default function PlaywireScript() {
  return <PlaywireRamp />
}

playwire_unit.tsx

import { RampUnit } from "pw-react-component"

export default function PlaywireUnit({ type, cssClass = "" }) {
  return <RampUnit type={type} cssClass={cssClass} />
}
ColeTownsend commented 10 months ago

I had a similar solution but I'm using the NextJS App Router.

Ad Scripts

Ramp scripts were added within the layout.tsx similar to how Next.js documents adding 3rd party scripts. They take care of the optimization by making the script load afterInteractive and make sure it only loads once. I'll probably experiment with offloading to a web worker for better performance.

<RampScripts />

"use client";

import Script from "next/script";

export default function RampScripts() {
  return (
    <>
      <Script async id="window-ramp">{`
          window.ramp = window.ramp || {}; window.ramp.que = window.ramp.que || []; window.ramp.passiveMode = true;
      `}</Script>
      <Script async id="pw-ramp" src="//cdn.intergient.com/RAMP/ID/ramp.js" />

      <Script async data-cfasync="false" id="ga-pw-config">
        {`
          window._pwGA4PageviewId = ''.concat(Date.now());
          window.dataLayer = window.dataLayer || [];
          window.gtag = window.gtag || function () {
            dataLayer.push(arguments);
          };
          gtag('js', new Date());
          gtag('config', 'G-TAG-FROM-PW', { 'send_page_view': false });
          gtag(
            'event',
            'ramp_js',
            {
              'send_to': 'G-TAG-FROM-PW',
              'pageview_id': window._pwGA4PageviewId
            }
          );
          `}
      </Script>
    </>
  );
}

Inserting Ad

This was also placed within the layout.tsx file within the route path we wanted to display them on.

"use client";

import { usePathname, useSearchParams } from "next/navigation";
import Script from "next/script";
import { useEffect } from "react";

export default function DynamicAdScripts() {
  const pathname = usePathname();
  const searchParams = useSearchParams();

  useEffect(() => {
    console.log("Ramp Use Effect");
    if (pathname && !pathname.includes("page-we-want-them-on")) {
      if (window.ramp && window.ramp.destroyUnits) {
        window.ramp.destroyUnits("all");
      }
    }
  }, [pathname, searchParams, window.ramp]);
  return (
    <>
      <Script id="pw-units" async data-cfasync="false">
        {`
          var pwUnits = [
            {
              type: "bottom_rail",
            },
            {
              type: "trendi_video",
            }
          ]

          var initDynamic = function () {
            window.ramp
            // pass in the array where you defined the units
            .addUnits(pwUnits)
            .then(() => {
              // then show the units
              ramp.displayUnits()
            }).catch( (e) =>{
              // catch errors
              window.ramp.displayUnits()
              console.error(e)
            })
          }
          window.ramp.que.push(initDynamic);
      `}
      </Script>
    </>
  );
}

Static Ad Units

In a similar manner to the react RampUnit we built our own unit that we insert ourselves. We use a ref to track them

"use client";

import { useEffect, useMemo, useRef } from "react";
import { usePathname, useSearchParams } from "next/navigation";

export const BrowseAdsComponent = () => {
  const adsInitialised = useRef(false);
  const pathname = usePathname();
  const searchParams = useSearchParams();

  const units = [
      {
        selectorId: `pwDeskMedRectBtf1`,
        type: "med_rect_btf",
      },
      {
        selectorId: `pwDeskMedRectBtf2`,
        type: "med_rect_btf",
      },
    ]

 const init = function () {
      window.ramp
        // pass in the array 'pwUnits' defined right above
        .addUnits(units)
        .then(() => {
          adsInitialised.current = true;
          window.ramp.displayUnits();
        })
        .catch((e: any) => {
          // catch errors
          window.ramp.displayUnits();
          console.error(e);
        });
    };
    if (!adsInitialised.current) {
      window.ramp.que.push(init);
    }

  useEffect(() => {
    if (!adsInitialised.current) {
      window.ramp.que.push(init);
    }
  }, [units, pathname, searchParams]);

  useEffect(() => {
    if (adsInitialised.current === true) {
      window.ramp.destroyUnits(["pwDeskMedRectBtf1", "pwDeskMedRectBtf1"]);
    }
  }, [pathname, searchParams]);

  return null;
};
const MediumRectangle = ({ number }: {number: number) => {
  return (
    <div ref={adsInitialised} data-pw-desk="med_rect_btf" id={`pwDeskMedRectBtf${number}`}></div>
  );
};