Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor tracker into importable TS module #143

Merged
merged 23 commits into from
Jan 15, 2025
Merged

Conversation

benvinegar
Copy link
Owner

@benvinegar benvinegar commented Jan 10, 2025

Refs #83

This patch does a few things:

  • Refactors the tracker code into modules
  • Exposes a basic public API for tracking pageviews (docs below)
  • Removes or rewrites nearly all Fathom Lite code (I no longer consider this a fork)
    • Makes HTTP requests via XMLHttpRequest instead of new Image
    • Reduces code for handling legacy initialization method (e.g. via counterscale.q global vars) into a slim compatibility layer
  • There are now 2 Vite builds:
    1. Builds the importable module (and exports TypeScript definition files) into dist/module
    2. Builds the self-executing loader script into dist/loader/tracker.js

Proposed API

Install via your package manager:

npm install @counterscale/tracker

To automatically track pageviews:

import * as Counterscale from "@counterscale/tracker";

Counterscale.init({
  siteId: "my-site-id",
  reporterUrl: "https://my-counterscale-deployment.pages.dev/collect"
});

To manually track pageviews:

import * as Counterscale from "@counterscale/tracker";
Counterscale.init({
  siteId: "my-site-id",
  reporterUrl: "https://my-counterscale-deployment.pages.dev/collect",
  autoTrackPageviews: false
});

// will use current url, referrer, etc from browser
Counterscale.trackPageview();

// manually specify url or other params
Counterscale.trackPageview({
  url: "http://mysite.biz/my/url"
});

Open Questions

  1. Instead of reporterUrl, should this just be DSN like Sentry uses? Seems redundant to have to specify /collect.

  2. Plausible uses a method approach for auto-tracking pageviews, something like:

const {autoTrackPageviews} = Counterscale({
  siteId: "my-site-id",
  reporterUrl: "...",
});

autoTrackPageviews();

I'm of the mind to simplify as much as possible and avoid people having to write multiple statements for what will be the 90% default case, but I'm probably missing something. Thoughts?

Copy link

codecov bot commented Jan 10, 2025

Codecov Report

Attention: Patch coverage is 89.16667% with 13 lines in your changes missing coverage. Please review.

Project coverage is 84.31%. Comparing base (e1aaa9a) to head (fa8d7f2).
Report is 2 commits behind head on main.

Files with missing lines Patch % Lines
packages/tracker/src/lib/track.ts 87.75% 6 Missing ⚠️
packages/tracker/src/index.ts 73.68% 5 Missing ⚠️
packages/tracker/src/lib/instrument.ts 86.66% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #143      +/-   ##
==========================================
+ Coverage   84.15%   84.31%   +0.15%     
==========================================
  Files          34       39       +5     
  Lines        2386     2512     +126     
  Branches      274      302      +28     
==========================================
+ Hits         2008     2118     +110     
- Misses        370      386      +16     
  Partials        8        8              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@thecodedrift
Copy link

Here by request from Bluesky 🫶🏻

I think it’s fine, but Counterscale looks like a singleton; you can probably discard the returns from the init function in favor of an import, ie

import { trackPageview } from...

This then lets someone easily get to counterscale functions even when using a bundler and deep within their app.

I’d also make autotrack the default and use a “disableAutotrack” option. This removes one more piece of the setup for most users.

I wouldn't worry too much about DSN v URL naming. endpoint is another option for naming if you want to bikeshed a bit.

Suggested result:

import { Counterscale, trackPageview } from "@counterscale/tracker";

Counterscale({
  siteId: "my-site-id",
  endpoint: "https://my-counterscale-deployment.pages.dev",
  // disableAutotrack: true
});

trackPageview(location.href)

@benvinegar
Copy link
Owner Author

benvinegar commented Jan 10, 2025

Counterscale looks like a singleton

It isn't. You can do this, for example:

let trackPageviewSiteA = Counterscale({
  siteId: "siteA"
  reporterUrl: "..."
}).trackPageview;

let trackPageviewSiteB = Counterscale({
  siteId: "siteB",
  reporterUrl: "..."
}).trackPageview;

trackPageviewSiteA();

trackPageviewSiteB();

Or you could similarly report the event to multiple Counterscale servers.

This then lets someone easily get to counterscale functions even when using a bundler and deep within their app.

I think this is still true as-is.

Okay, I understand what you're saying. I think though, if I do that, we basically are committing to making it a singleton (the state has to be global for that to work) which I don't love. But you're right about ease of use, etc.

@benvinegar
Copy link
Owner Author

I’d also make autotrack the default and use a “disableAutotrack” option. This removes one more piece of the setup for most users.

Eh it'll be copy-paste for most people so not too worried about that.

@benvinegar benvinegar merged commit 0749c9c into main Jan 15, 2025
3 checks passed
@benvinegar benvinegar deleted the refactor-tracker branch January 15, 2025 19:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants