next中引用外部脚本

1,268 阅读4分钟

由于在web开发中的项目需要商业化,因此需要引用一些外部脚本,比如谷歌广告、谷歌分析等脚本,本文针对在next项目中如何快速引用外部脚本做一个总结

1、next引用脚本的方式:

a、引用外部脚本

import Script from 'next/script'
<Script src="https://securepubads.g.doubleclick.net/tag/js/gpt.js" />
  • strategy属性:
    • beforeInteractive:在任何 Next.js 代码之前以及任何页面水合发生之前加载(主要在next相关js代码加载之前)
    • afterInteractive:尽早加载,但在页面发生一些水合作用之后(主要在next相关js代码加载之后)
    • lazyOnload:在浏览器空闲时加载

nextpages路由模式下分别测试:

一、使用 beforeInteractive

//在pages路由下:  
      <Script
        src="https://polyfill.io/v3/polyfill.min.js?features=IntersectionObserverEntry%2CIntersectionObserver"
        strategy="beforeInteractive"
      /> 
//案列地址:https://solutions-script-component-strategies.vercel.app/polyfill
//案列代码:https://github.com/vercel/examples/blob/main/solutions/script-component-strategies/pages/polyfill.tsx

查看pages路由测试结果: image.png

image.png

总结:由图可知主要加载顺序是polyfill.io/v3/polyfill>next的脚本,同时主要使用的是defer脚本加载方式


二、使用 afterInteractive,策略的默认值

//在pages路由下:   
      <Script
        src="https://js.stripe.com/v3/"
        strategy="afterInteractive"
        onLoad={() =>
          addLog(`script loaded correctly, window.Stripe has been populated`)
        }
      />
//案列地址:https://solutions-script-component-strategies.vercel.app/stripe
//案列代码:https://github.com/vercel/examples/blob/main/solutions/script-component-strategies/pages/stripe.tsx

image.png

image.png 总结:由图可知主要加载顺序是next>js.stripe.com/v3/的脚本,是通过next下客户端脚本main脚本,查看源码发现是调用document.createElement("script")document.body.appendChild(el) 动态追加script标签

image.png

三、使用 lazyOnload

//在pages路由下:   
      <Script
        src="https://connect.facebook.net/en_US/sdk.js"
        strategy="lazyOnload"
        onLoad={() =>
          addLog(`script loaded correctly, window.FB has been populated`)
        }
      />
//案列地址:https://solutions-script-component-strategies.vercel.app/fb
//案列代码:https://github.com/vercel/examples/blob/main/solutions/script-component-strategies/pages/fb.tsx

image.png

image.png 总结:由图可知主要加载顺序是next>connect.facebook.net/en_US/sdk的脚本,是通过next下客户端脚本main脚本,查看源码分析是由document.readyState === "complete"或者监听load事件后调用document.createElement("script")document.body.appendChild(el)动态追加script标签


nextapp路由下测试

一、使用 beforeInteractive

image.png image.png 总结:由图可知,因为使用了preload,导致加载几乎一样。


二、使用 afterInteractive,策略的默认值

image.png

image.png

image.png 总结:由图可知,因为使用了preload,导致加载几乎一样,加载位置还是可以看出相对于


三、使用 lazyOnload

image.png

image.png

image.png 总结:由图可知,懒加载的脚本也是在next脚本加载完后,由document.readyState === "complete"或者监听load事件后调用document.createElement("script")document.body.appendChild(el)动态追加script标签

b、引用内联脚本

也支持策略,此处就可以直接使用谷歌分析代码,全局通用

      <Script id="Analytics">
        {`       
         window.dataLayer = window.dataLayer || [];
        function gtag() { dataLayer.push(arguments); }
        gtag('js', new Date());
        gtag('config', "xxxxxx");
        `}
      </Script>

2、加载方式说明

  1. async 属性的脚本执行顺序:

    • 异步加载的脚本会在下载完成后立即执行,而不会等待其他资源(包括其他脚本)的加载和执行。
    • 如果页面中有多个带有 async 属性的脚本,它们的执行顺序将取决于它们的下载完成时间。即使在 HTML 中按顺序定义了这些脚本,它们也可能以任意顺序执行。
  2. defer 属性的脚本执行顺序:

    • 延迟加载的脚本会按照它们在 HTML 中的顺序执行。这意味着先出现在 HTML 中的脚本会先执行,后出现的脚本会后执行。
    • defer 属性使得脚本的执行被延迟到 HTML 解析完成之后,但在 DOMContentLoaded 事件之前。
  3. preload

    • 预加载脚本:preload 属性告诉浏览器在页面加载期间预加载脚本文件,即使在遇到 <script> 标签之前也可以开始下载脚本文件。这样,在需要执行脚本时,可以更快地从浏览器缓存中获取已经下载好的脚本文件。
    • 并行下载:通过使用 preload 属性,浏览器可以并行下载脚本文件,这样可以更快地获取脚本资源,而不会阻塞其他资源的下载和页面渲染。
    • 提前解析和编译:预加载脚本还可以让浏览器在下载阶段就开始解析和编译脚本文件,以便在需要执行时能够更快地执行。这有助于减少执行时的延迟,并提高页面的响应速度。
    • preload 属性仅在支持该功能的现代浏览器中起作用。对于不支持 preload 属性的旧浏览器,它将被忽略,而脚本将按照正常的方式进行加载和执行

3、本地项目使用

37b354b6-1f45-48d5-a337-9b022639a1d1 (1).gif 84407efd-704b-4df7-8aa6-95fbe67f5366 (1).gif 由于需要在本地测试广告、使用adsense本地测试效果,出现测试广告的概率很低,因此使用admanager来测试。使用admanager中间测试时候会出现一些细节问题:

  • admanager的gpt代码,需要给页面上的元素设置id,后续广告展示会直接放在这个容器里,如果切换其他页面,这个id不变的话广告会异常。
  • 因为next第一次页面刷新是服务端渲染的页面,在这个页面访问其他页面就是客户端渲染了。两个页面来回切换,其实还是处于一个页面而已,会导致广告代码重复使用
        <Script
          src="https://securepubads.g.doubleclick.net/tag/js/gpt.js"
        />
"use client";
import { Skeleton } from "../../module/commom/skeleton";
import { useEffect, useRef } from "react";
export interface IHorizontalAdProps {
  id: number;
}
export default function HorizontalAd({ id }: IHorizontalAdProps) {
  const adRef = useRef<HTMLDivElement>(null);
  useEffect(() => {
    const current = adRef.current;
    if (current) {
      const newId = `ad-${Date.now()}-${id}`;
      current?.setAttribute("id", newId);
      const googletag = (window.googletag = window.googletag || { cmd: [] });
      googletag.cmd.push(function () {
        const responsiveAdSlot = googletag
          .defineSlot(
            "/6355419/Travel/Europe",
            [
              [300, 250],
              [728, 90],
              [750, 200],
            ],
            `${newId}`
          )
          .addService(googletag.pubads());

        const mapping = googletag
          .sizeMapping()
          .addSize(
            [1440, 768],
            [
              [750, 200],
              [728, 90],
            ]
          )
          .addSize([0, 0], [300, 250])
          .build();

        responsiveAdSlot.defineSizeMapping(mapping);

        googletag.enableServices();
        googletag.cmd.push(() => {
          googletag.display(`${newId}`);
        });
      });
    }
  }, [id]);
  return (
    <>
      <div className="flex flex-col justify-center items-center  w-full h-[320px] mt-[.89rem] bg-[#222]  xl:rounded-[.89rem] xl:mt-[.89rem] xl:h-[13.11rem]">
        Ad
        <div
          ref={adRef}
          className="w-[300px] h-[250px] xl:w-[700px] xl:h-[200px]"
        >
          <Skeleton num={1} className="smn:w-full smn:h-full"></Skeleton>
        </div>
      </div>
    </>
  );
}

4、参考