nuxt2框架如何安装partytown

262 阅读3分钟

目前nuxt项目想使用partytown,nuxt3 可以直接安装Nuxtjs/partytown来安装partytown。nuxt2 2.17.0以上版本可以通过安装nuxtjs/bridge再安装nuxtjs/partytown实现partytown的安装。

但是如果nuxt版本在2.17.0以下,并没有找到适配插件,这里我化用了nuxtjs/partytown写了相关代码,以安装partytown。

1.安装builder.io/partytown。

方法:

  1. 直接在项目package.json的dependencies配置里加上条目:"@builder.io/partytown": "^0.6.0"
  2. 执行命令行yarn install.

2.目录modules,新建模块partytown,新建文件夹index.js

image.png

index.js文件内容:

import { join } from 'path';
import { promises } from 'fs';
import { genObjectFromRawEntries } from 'knitwork';
import { defineNuxtModule, isNuxt2 } from '@nuxt/kit';
import { libDirPath, copyLibFiles } from '@builder.io/partytown/utils';
import { withLeadingSlash, withTrailingSlash, withoutTrailingSlash } from 'ufo';
import path from 'path';

const module = defineNuxtModule({
  meta: {
    name: "@nuxtjs/partytown",
    configKey: "partytown"
  },
  // partytown文件路径。partytown官方推荐将插件lib目录下文件复制到自己的代码里,
  // 或者放到CDN上,直接放到CDN上我没试过,如果复制到自己的文件夹下,比如Nuxt2项目的static目录下partytown文件,lib配置应该为'/partytown/',下面这个配置,用的是读取插件里的目录
  defaults: (nuxt) => ({
    debug: false,
    forward: [],
    lib: "~partytown" 
  }),
  async setup(options, nuxt) {
    const fns = ["resolveUrl", "get", "set", "apply"];
    options.lib = withLeadingSlash(withTrailingSlash(options.lib));
    const rawConfig = Object.entries(options).map(
      ([key, value]) => [key, fns.includes(key) ? value : JSON.stringify(value)]
    );
    const renderedConfig = genObjectFromRawEntries(rawConfig).replace(/\s*\n\s*/g, " ");
    const partytownSnippet = await promises.readFile(path.resolve(__dirname, './partytown.js'), "utf-8"); //读取partytown会展示在页面内的Snippet代码。这块代码可以继续使用nuxtjs/partytown原生的代码,那个读取的是插件里的partytown.js。

    if (isNuxt2()) {
      const nuxt2Options = nuxt.options;
      nuxt2Options.head = nuxt2Options.head || {};
      nuxt2Options.head.__dangerouslyDisableSanitizersByTagID = nuxt2Options.head.__dangerouslyDisableSanitizersByTagID || {};
      nuxt2Options.head.__dangerouslyDisableSanitizersByTagID.partytown = ["innerHTML"];
      nuxt2Options.head.__dangerouslyDisableSanitizersByTagID["partytown-config"] = ["innerHTML"];
      nuxt2Options.head.script.unshift(
        { id: "partytown-config", hid: "partytown-config", innerHTML: `partytown = ${renderedConfig}` },
        { id: "partytown", hid: "partytown", innerHTML: partytownSnippet }
      ); //将partytown的内容插入页面

      // nuxtjs/gtm希望被partytown处理。这是我安装partytown的最主要原因,因为项目安装了google tag manager,且存在多语言多站点环境。所以使用了nuxtjs/gtm,如果项目没有多语言多站点这种要求,可以直接参考partytown官网view page source后看到的gtm安装代码的配置进行配置。官网文档里的写法我没有成功。
      // gtm那边又有十几个平台的数据追踪,希望通过partytown把这些数据追踪代码放到web worker工作。
      // 但是发现后续这块还得有更多配置,之后处理完毕再进行这块进度。
      let HeaderScript =nuxt2Options.head.script; 
      let gtmScript = nuxt2Options.head.script.find((script) => script.hid === 'gtm-script');
      if (gtmScript) {
        HeaderScript.splice(HeaderScript.indexOf(gtmScript), 1);
        gtmScript.innerHTML = `if(!window._gtm_init){window._gtm_init=1;(function(w,n,d,m,e,p){w[d]=(w[d]==1||n[d]=='yes'||n[d]==1||n[m]==1||(w[e]&&w[e][p]&&w[e][p]()))?1:0})(window,navigator,'doNotTrack','msDoNotTrack','external','msTrackingProtectionEnabled');(function(w,d,s,l,x,y){w[x]={};w._gtm_inject=function(i){w[x][i]=1;w[l]=w[l]||[];w[l].push({'gtm.start':new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],j=d.createElement(s);j.crossOrigin='true';j.async=true;j.type='text/partytown';j.src='https://www.googletagmanager.com/gtm.js?id='+i;f.parentNode.insertBefore(j,f);window.dispatchEvent(new CustomEvent('ptupdate'));}})(window,document,'script','dataLayer','_gtm_ids','_gtm_inject')}`;
        nuxt2Options.head.script.push(gtmScript);
      }
      

      nuxt.hook("generate:done", async () => {
        await copyLibFiles(join(nuxt.options.generate.dir, options.lib));
      });

      nuxt.hook("render:setupMiddleware", async (app) => {
        const serveStatic = await import('serve-static').then(
          (r) => r.default || r
        );
        // 这块是做什么我没搞懂,其实可以注释掉,如果要使用自己的目录下的文件,这里就需要注释了,不然就会稳定的读取node_modules目录下的插件代码。
        app.use(withoutTrailingSlash(withLeadingSlash(options.lib)), serveStatic(libDirPath()));
      });
    }
  }
});

export { module as default };

3.nuxt.config.js文件增加配置

modules:[
    ...,
    '~/modules/partytown', //partytown模块
],
partytown: {
   forward: [
     'dataLayer.push', // google。这个配置了之后dataLayer.push函数就会在web worker里工作了。
     'gtag',
   ],
   debug: process.env.NODE_ENV === 'development', // 开发者模式开启debug模式,不然关闭debug模式
},
head: {
    script:[
        {
            hid: 'gtm',
            type: 'text/partytown',
            innerHTML: `
                window.dataLayer = window.dataLayer || [];
                window.gtag = function gtag(){dataLayer.push(arguments);} // gtm里有gtag代码
            `
        }
    ],
    __dangerouslyDisableSanitizersByTagID: {
        gtm: ['innerHTML'],
    },
}

4.重启项目,就可以看到gtm代码在partytown线程工作了。

image.png