Skip to content

Commit

Permalink
Add unique page views to our scripts
Browse files Browse the repository at this point in the history
  • Loading branch information
adriaandotcom committed Nov 14, 2019
1 parent 85af2c9 commit 9e60765
Show file tree
Hide file tree
Showing 7 changed files with 88 additions and 31 deletions.
2 changes: 1 addition & 1 deletion dist/default.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion dist/external.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

27 changes: 22 additions & 5 deletions minify.js
@@ -1,30 +1,35 @@
const UglifyJS = require('uglify-js')
const fs = require('fs')
const esprima = require('esprima')

const green = '\x1b[32m%s\x1b[0m'
const yellow = '\x1b[33m%s\x1b[0m'
// const red = '\x1b[31m%s\x1b[0m'
const red = '\x1b[31m%s\x1b[0m'

const files = {
default: {
type: 'js',
original: `${__dirname}/src/default.js`,
minified: `${__dirname}/dist/default.js`,
prepend: ['/* Simple Analytics - Privacy friend analytics (docs.simpleanalytics.com/script) */', ''],
append: []
},
embed: {
type: 'js',
original: `${__dirname}/src/embed.js`,
minified: `${__dirname}/dist/embed.js`,
prepend: ['/* Simple Analytics - Privacy friend analytics (docs.simpleanalytics.com/embed-graph-on-your-site) */', ''],
append: []
},
external: {
type: 'js',
original: `${__dirname}/src/external.js`,
minified: `${__dirname}/dist/external.js`,
prepend: ['/* Simple Analytics - Privacy friend analytics (docs.simpleanalytics.com/script) */', ''],
append: []
},
iframe: {
type: 'html',
original: `${__dirname}/src/iframe.js`,
minified: `${__dirname}/dist/iframe.html`,
prepend: ['<!DOCTYPE html>', '<title>SA</title>', '<script>'],
Expand All @@ -42,16 +47,28 @@ const options = {

for (const file in files) {
if (files.hasOwnProperty(file)) {
const { original, minified, prepend, append } = files[file]
const { type, original, minified, prepend, append } = files[file]
const name = file.toUpperCase()

const contents = fs.readFileSync(original, 'utf8')
const { code, warnings } = UglifyJS.minify(contents, options)
for (const warning of (warnings || [])) console.warn(yellow, `[MINIFY][${name}] ${warning}`)
const nginxCode = code.replace('simpleanalytics.example.com', '<!--# echo var="http_host" default="" -->')
const lines = [...prepend, nginxCode, ...append]
fs.writeFileSync(minified, lines.join('\n'))
const bytes = new TextEncoder('utf-8').encode(lines.join('\n')).length
const lines = [...prepend, nginxCode, ...append].join('\n')

const validate = type === 'js' ? lines.replace('<!--# echo var="http_host" default="" -->', '') : code

try {
esprima.parseScript(validate)
} catch (error) {
const { index, lineNumber, description } = error
console.log(red, `[MINIFY][${name}][ERROR] ${original.split('/').pop()} ${description} at line ${lineNumber} position ${index}`)
continue
}

fs.writeFileSync(minified, lines)
const bytes = new TextEncoder('utf-8').encode(lines).length

console.log(green, `[MINIFY][${name}] Minified ${original.split('/').pop()} into ${bytes} bytes`)
}
}
5 changes: 5 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion package.json
Expand Up @@ -18,7 +18,9 @@
"url": "https://github.com/simpleanalytics/scripts/issues"
},
"homepage": "https://github.com/simpleanalytics/scripts#readme",
"dependencies": {},
"dependencies": {
"esprima": "^4.0.1"
},
"devDependencies": {
"nodemon": "^1.19.1",
"uglify-js": "^3.6.0"
Expand Down
46 changes: 30 additions & 16 deletions src/default.js
@@ -1,9 +1,5 @@
/* eslint-env browser */

// We use https://jscompress.com to compress our script so you can test
// if this script is indeed the same script as the minified version we
// published on https://cdn.simpleanalytics.io/hello.js

(function(window, hostname, path, cdn) {
if (!window) return;

Expand All @@ -13,22 +9,25 @@
var cdnUrl = cdn ? protocol + cdn : (apiUrl + '.js');
var con = window.console;

// A simple log function so the user knows why a request is not being send
var warn = function(message) {
if (con && con.warn) con.warn('Simple Analytics: ' + message);
}

try {
var nav = window.navigator;
var loc = window.location;
var doc = window.document;
var userAgent = nav.userAgent;
var dis = window.dispatchEvent;
var perf = window.performance;
var lastSendUrl;
var notSending = 'Not sending requests ';

var script = doc.querySelector('script[src="' + cdnUrl + '"]');
var mode = script ? script.getAttribute('data-mode') : null;

// A simple log function so the user knows why a request is not being send
var warn = function(message) {
if (con && con.warn) con.warn('Simple Analytics: ' + message);
}
var attr = function(script, attribute) { return script && script.getAttribute('data-' + attribute) }
var mode = attr(script, 'mode')
var skipDNT = attr(script, 'skip-dnt') === 'true'

// We do advanced bot detection in our API, but this line filters already most bots
if (userAgent.search(/(bot|spider|crawl)/ig) > -1) return warn(notSending + 'because user agent is a robot');
Expand All @@ -44,11 +43,8 @@
if (lastSendUrl === url) return;
lastSendUrl = url;

// Skip prerender requests
if ('visibilityState' in doc && doc.visibilityState === 'prerender') return warn(notSending + 'when prerender');

// Don't track when Do Not Track is set to true
if ('doNotTrack' in nav && nav.doNotTrack === '1') return warn(notSending + 'when doNotTrack is enabled');
if (!skipDNT && 'doNotTrack' in nav && nav.doNotTrack === '1') return warn(notSending + 'when doNotTrack is enabled');

// Don't track when localhost
if (loc.hostname === 'localhost' || loc.protocol === 'file:') return warn(notSending + 'from localhost');
Expand All @@ -63,6 +59,24 @@
if (doc.referrer && !isPushState) data.referrer = doc.referrer;
if (window.innerWidth) data.width = window.innerWidth;

// We put new code always in a try block to prevent huge issues
try {
// Check if back, forward or reload buttons are being use in modern browsers
var backModern = (perf && perf.getEntriesByType && perf.getEntriesByType('navigation')[0] && perf.getEntriesByType('navigation')[0].type)
? ['reload', 'back_forward'].indexOf(perf.getEntriesByType('navigation')[0].type) > -1
: null

// Check if back, forward or reload buttons are being use in older browsers
var back = typeof backModern === 'boolean'
? backModern
: perf && perf.navigation && perf.navigation.type && [perf.navigation.TYPE_RELOAD, perf.navigation.TYPE_BACK_FORWARD].indexOf(perf.navigation.type) > -1

// We set unique variable based on pushstate or back navigation, if no match we check the referrer
data.unique = isPushState || back ? false : doc.referrer && doc.referrer.split('/')[2] !== loc.hostname;
} catch (error) {
// nothing
}

try {
data.timezone = Intl.DateTimeFormat().resolvedOptions().timeZone
} catch (error) {
Expand Down Expand Up @@ -106,9 +120,9 @@

post();
} catch (e) {
if (con && con.error) con.error(e);
warn(e.message);
var url = apiUrl + '.gif';
if (e && e.message) url = url + '?error=' + encodeURIComponent(e.message);
if (e.message) url = url + '?error=' + encodeURIComponent(e.message);
new Image().src = url;
}
})(window, 'api.simpleanalytics.io', '/post', 'cdn.simpleanalytics.io/hello.js');
33 changes: 26 additions & 7 deletions src/external.js
Expand Up @@ -7,9 +7,15 @@
var host = loc.hostname
var doc = window.document
var con = window.console
var perf = window.performance
var uri = '//' + hostname
var targetOrigin = 'https://' + hostname

// A simple log function so the user knows why a request is not being send
var warn = function(message) {
if (con && con.warn) con.warn('Simple Analytics: ' + message)
}

try {
var userAgent = nav.userAgent
var dis = window.dispatchEvent
Expand All @@ -23,11 +29,6 @@
var skipDNT = attr(script, 'skip-dnt') === 'true'
var functionName = attr(script, 'sa-global') || 'sa'

// A simple log function so the user knows why a request is not being send
var warn = function(message) {
if (con && con.warn) con.warn('Simple Analytics: ' + message)
}

// Don't track when host is localhost
if (host === 'localhost') return warn(notSending + 'from localhost')

Expand Down Expand Up @@ -65,6 +66,24 @@
if (cleanRef && !isPushState) data.referrer = cleanRef
if (window.innerWidth) data.width = window.innerWidth

// We put new code always in a try block to prevent huge issues
try {
// Check if back, forward or reload buttons are being use in modern browsers
var backModern = (perf && perf.getEntriesByType && perf.getEntriesByType('navigation')[0] && perf.getEntriesByType('navigation')[0].type)
? ['reload', 'back_forward'].indexOf(perf.getEntriesByType('navigation')[0].type) > -1
: null

// Check if back, forward or reload buttons are being use in older browsers
var back = typeof backModern === 'boolean'
? backModern
: perf && perf.navigation && perf.navigation.type && [perf.navigation.TYPE_RELOAD, perf.navigation.TYPE_BACK_FORWARD].indexOf(perf.navigation.type) > -1

// We set unique variable based on pushstate or back navigation, if no match we check the referrer
data.unique = isPushState || back ? false : doc.referrer && doc.referrer.split('/')[2] !== loc.hostname;
} catch (error) {
// nothing
}

try {
data.timezone = Intl.DateTimeFormat().resolvedOptions().timeZone
} catch (error) {
Expand Down Expand Up @@ -144,9 +163,9 @@

if (!loading && queue.length) loadIframe()
} catch (e) {
if (con && con.error) con.error(e)
warn(e.message)
var url = uri + '/image.gif'
if (e && e.message) url = url + '?error=' + encodeURIComponent(e.message)
if (e.message) url = url + '?error=' + encodeURIComponent(e.message)
new Image().src = url
}
})(window, 'simpleanalytics.example.com')

0 comments on commit 9e60765

Please sign in to comment.