为vitepress静态网站增加访问统计代码

最近写自研的一个软件产品文档,首次使用了vitepress。看着官方文档,磕磕绊绊的算是完成了一版。比如:

  • 构建可视化、动态数据交互界面的软件简介
  • 实时数据通讯
    等等

在为文档网站添加访问统计代码时,遇到了些困难。网上搜索和掘金都没有合适的答案。这里介绍我的具体实现,以供需要的同学使用。

一、vitepress的相关配置

为vitepress静态网站增加统计代码,需要在2个地方进行配置:head 和 路由。

1.1 head 配置

我们要增加网站访问统计代码。无论你用的是google还是百度,或者其他第三方统计服务,都需要在head中进行配置。

在 .vitepress/config.ts 文件中,配置如下:

 head: [
    // ... 其他部分的配置,比如
    
    [
      'script',
      {},
      `
      window._hmt = window._hmt || [];
      (function() {
        var hm = document.createElement("script");
        hm.src = "https://hm.baidu.com/hm.js?abcdefgeggsdfsdf123123";
        var s = document.getElementsByTagName("script")[0]; 
        s.parentNode.insertBefore(hm, s);
      })();
      `,
    ],
  ],

由于google无法访问,又不想花银子,所以这里以某度统计的免费版为例。这里代码中和某度统计官方文档不同的地方,在与第 8 行。(不清楚如何将第8行高亮显示,请知道的同学留言告诉我 ??)

window._hmt = window._hmt || [];

官网文档中的实例是:var _hmt = _hmt || [];

之所以要写入全局变量window中,是为了下面介绍的第2项配置。在第二项配置中,会读取这个 _hmt 变量。如果不存入 window 对象中,则读取不到。

1.2 路由配置

vitepress是基于文件路径的路由,并且构建生成的都是静态的html页面。根据vitepress的官网介绍,vitepress构建的实质上是一个单页面应用(SPA)。

而用户在这个SPA应用中,会访问不同的静态页面。我们必须把他所有不同的访问url都进行统计记录下来。

在SPA应用中,那么仅仅在head部分增加一个js函数来发送访问统计数据到统计平台,就显得不够了。因为这个js函数在spa中,只会执行一次。

既然是spa,那么页面的跳转,就离不开router,我们只需要跟踪路由的变化即可。

1.2.1 主题配置项

我们先来看看主题的主要配置项:

interface EnhanceAppContext {
    app: App;
    router: Router;
    siteData: Ref<SiteData>;
}

interface Theme {
    Layout?: Component;
    enhanceApp?: (ctx: EnhanceAppContext) => Awaitable<void>;
    extends?: Theme;
    /**
     * @deprecated can be replaced by wrapping layout component
     */
    setup?: () => void;
    /**
     * @deprecated Render not found page by checking `useData().page.value.isNotFound` in Layout instead.
     */
    NotFound?: Component;
}

其中:enhanceApp是一个参数为EnhanceAppContext的函数。而EnhanceAppContext的一个属性是Router类型。我们再来看看这个Router:

interface Router {
    /**
     * Current route.
     */
    route: Route;
    /**
     * Navigate to a new URL.
     */
    go: (to?: string) => Promise<void>;
    /**
     * Called before the route changes. Return `false` to cancel the navigation.
     */
    onBeforeRouteChange?: (to: string) => Awaitable<void | boolean>;
    /**
     * Called before the page component is loaded (after the history state is
     * updated). Return `false` to cancel the navigation.
     */
    onBeforePageLoad?: (to: string) => Awaitable<void | boolean>;
    /**
     * Called after the route changes.
     */
    onAfterRouteChanged?: (to: string) => Awaitable<void>;
}

从上面的几个接口定义可以看出,EnhanceAppContext的router属性,实际上是vue-router实例的一个代理包装。它有一个当前路由的对象、go方法(跳转方法)和3个事件。根据3个事件的命名,我们可以发现onBeforeRouteChange事件,就是我们需要的方法。即:在路由改变之前进行处理。

1.2.2 自定义路由改变事件

我原来的主题配置文件 ( .vitepress/theme/index.js ) 是这样的:

import './tailwind.postcss';
import DefaultTheme from 'vitepress/theme';
export default { ...DefaultTheme };

我的目的很明确,主要是写文档。vitepress的默认主题我觉着已经够用了。由于对默认的主题样式不熟悉,同时为了增加一些外部的样式以简化文档页面一些自定义的样式,我引入了 tailwind.css,但是主题文件很简单。只导出了默认的主题。

现在对这个文件内容,做出如下改变:

import './tailwind.postcss';
import DefaultTheme from 'vitepress/theme';

DefaultTheme.enhanceApp = ({ app, router, siteData }) => {
  router.onBeforeRouteChange = (to) => {
    console.log('路由将改变为: ', to);
    if (typeof _hmt !== 'undefined') {
      _hmt.push(['_trackPageview', to]);
    }
  };
};
export default { ...DefaultTheme };

默认主题对象,是不具有enhanceApp属性的(上面的接口定义,该属性是可选的),因此我们手动定义他的内容即可。

在这改代码中 _hmt 就是上面文档介绍的,存入 window 对象的那个对象,如果不存入window,则在build文档时,会发生错误。其 push 方法,就是向某度统计发送当前路径的数据。

当然,这里的 onBeforeRouteChange 事件实现是向某度统计发送url路径。你可以根据实际的统计平台的接口要求,自己实现这一块的逻辑。原理是一样的。

实际运行情况如下:

vitepress增加数据统计.gif

可以看到,每一次的路由变化,控制台都输出了要跳转的url。都会发送一个 https://hm.baidu.com/hm.gif?cc=1&ck=1&cl=2xxx 的远程请求。这个请求地址,正是目标统计平台接收数据的地址。

至此,我们实现了为vitepress静态网站增加访问统计代码的功能目标。

本文由博客一文多发平台 OpenWrite 发布!