Merge pull request #178 from mikecao/dev

v0.39.0 - Tracker updates
This commit is contained in:
Mike Cao 2020-09-18 14:59:53 -07:00 committed by GitHub
commit 238251a9b4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 99 additions and 52 deletions

View File

@ -2,7 +2,7 @@ import React, { useRef } from 'react';
import { FormattedMessage } from 'react-intl';
import Button from 'components/common/Button';
import FormLayout, { FormButtons, FormRow } from 'components/layout/FormLayout';
import CopyButton from '../common/CopyButton';
import CopyButton from 'components/common/CopyButton';
export default function TrackingCodeForm({ values, onClose }) {
const ref = useRef();

View File

@ -23,6 +23,7 @@ export const useSession = use(async (req, res, next) => {
try {
session = await getSession(req);
} catch (e) {
console.error(e);
return serverError(res, e.message);
}

View File

@ -1,6 +1,6 @@
{
"name": "umami",
"version": "0.38.0",
"version": "0.39.0",
"description": "A simple, fast, website analytics alternative to Google Analytics. ",
"author": "Mike Cao <mike@mikecao.com>",
"license": "MIT",

View File

@ -11,6 +11,12 @@ export default function Test() {
return <h1>No id query specified.</h1>;
}
function handleClick() {
window.umami('Custom event');
window.umami.pageView('/fake', 'https://www.google.com');
window.umami.pageEvent('pageEvent', 'custom-type');
}
return (
<>
<Head>
@ -20,7 +26,7 @@ export default function Test() {
</Head>
<Layout>
<p>
Here you can test if your umami installation works. Open the network tab in your browser's
Here you can test if your umami installation works. Open the network tab in your browser
developer console and watch for requests to the url <b>collect</b>. The links below should
trigger page views. Clicking on the button should trigger an event.
</p>
@ -40,6 +46,10 @@ export default function Test() {
>
Button
</button>
<h2>Manual trigger</h2>
<button id="manual-button" type="button" onClick={handleClick}>
Button
</button>
</Layout>
</>
);

View File

@ -1,6 +1,5 @@
import 'dotenv/config';
import buble from '@rollup/plugin-buble';
import replace from '@rollup/plugin-replace';
import resolve from '@rollup/plugin-node-resolve';
import { terser } from 'rollup-plugin-terser';
@ -10,10 +9,5 @@ export default {
file: 'public/umami.js',
format: 'iife',
},
plugins: [
replace({ __DNT__: !!process.env.ENABLE_DNT }),
resolve(),
buble(),
terser({ compress: { evaluate: false } }),
],
plugins: [resolve(), buble(), terser({ compress: { evaluate: false } })],
};

View File

@ -1,6 +1,4 @@
import 'promise-polyfill/src/polyfill';
import 'unfetch/polyfill';
import { post, hook, doNotTrack } from '../lib/web';
import { doNotTrack, hook } from '../lib/web';
import { removeTrailingSlash } from '../lib/url';
(window => {
@ -13,28 +11,42 @@ import { removeTrailingSlash } from '../lib/url';
} = window;
const script = document.querySelector('script[data-website-id]');
const attr = key => script && script.getAttribute(key);
// eslint-disable-next-line no-undef
if (!script || (__DNT__ && doNotTrack())) return;
const website = attr('data-website-id');
const hostUrl = attr('data-host-url');
const autoTrack = attr('data-auto-track') !== 'false';
const dnt = attr('data-do-not-track') === 'true';
if (!script || (dnt && doNotTrack())) return;
const website = script.getAttribute('data-website-id');
const hostUrl = script.getAttribute('data-host-url');
const root = hostUrl
? removeTrailingSlash(hostUrl)
: new URL(script.src).href.split('/').slice(0, -1).join('/');
const screen = `${width}x${height}`;
const listeners = [];
let currentUrl = `${pathname}${search}`;
let currentRef = document.referrer;
/* Collect metrics */
const collect = (type, params) => {
const post = (url, data, callback) => {
const req = new XMLHttpRequest();
req.open('POST', url, true);
req.setRequestHeader('Content-Type', 'application/json');
req.onreadystatechange = () => {
if (req.readyState === 4) {
callback && callback();
}
};
req.send(JSON.stringify(data));
};
const collect = (type, params, uuid) => {
const payload = {
url: currentUrl,
referrer: currentRef,
website,
website: uuid,
hostname,
screen,
language,
@ -52,14 +64,55 @@ import { removeTrailingSlash } from '../lib/url';
});
};
const pageView = () => collect('pageview').then(() => setTimeout(loadEvents, 300));
const pageView = (url = currentUrl, referrer = currentRef, uuid = website) =>
collect(
'pageview',
{
url,
referrer,
},
uuid,
);
const pageEvent = (event_type, event_value) => collect('event', { event_type, event_value });
const pageEvent = (event_value, event_type = 'custom', url = currentUrl, uuid = website) =>
collect(
'event',
{
event_type,
event_value,
url,
},
uuid,
);
/* Handle history */
/* Handle events */
const loadEvents = () => {
document.querySelectorAll("[class*='umami--']").forEach(element => {
element.className.split(' ').forEach(className => {
if (/^umami--([a-z]+)--([a-z0-9_]+[a-z0-9-_]+)$/.test(className)) {
const [, type, value] = className.split('--');
const listener = () => pageEvent(value, type);
listeners.push([element, type, listener]);
element.addEventListener(type, listener, true);
}
});
});
};
const removeEvents = () => {
listeners.forEach(([element, type, listener]) => {
element && element.removeEventListener(type, listener, true);
});
listeners.length = 0;
};
/* Handle history changes */
const handlePush = (state, title, url) => {
removeEvents();
currentRef = currentUrl;
const newUrl = url.toString();
@ -70,40 +123,29 @@ import { removeTrailingSlash } from '../lib/url';
currentUrl = newUrl;
}
pageView();
pageView(currentUrl, currentRef);
setTimeout(loadEvents, 300);
};
history.pushState = hook(history, 'pushState', handlePush);
history.replaceState = hook(history, 'replaceState', handlePush);
/* Global */
/* Handle events */
if (!window.umami) {
const umami = event_value => pageEvent(event_value);
umami.pageView = pageView;
umami.pageEvent = pageEvent;
const removeEvents = () => {
listeners.forEach(([element, type, listener]) => {
element && element.removeEventListener(type, listener, true);
});
listeners.length = 0;
};
const loadEvents = () => {
document.querySelectorAll("[class*='umami--']").forEach(element => {
element.className.split(' ').forEach(className => {
if (/^umami--([a-z]+)--([a-z0-9_]+[a-z0-9-_]+)$/.test(className)) {
const [, type, value] = className.split('--');
const listener = () => pageEvent(type, value);
listeners.push([element, type, listener]);
element.addEventListener(type, listener, true);
}
});
});
};
window.umami = umami;
}
/* Start */
pageView();
if (autoTrack) {
history.pushState = hook(history, 'pushState', handlePush);
history.replaceState = hook(history, 'replaceState', handlePush);
if (!window.umami) {
window.umami = event_value => collect('event', { event_type: 'custom', event_value });
pageView(currentUrl, currentRef);
loadEvents();
}
})(window);