From 7f3e55418be9e755c5613033485e9abb0336c8d8 Mon Sep 17 00:00:00 2001 From: Vignesh Joglekar Date: Tue, 18 May 2021 03:36:12 -0500 Subject: [PATCH] Changes from static tracker script name assignments to dynamic (#786) Co-authored-by: Uku Taht --- lib/plausible_web/plugs/tracker.ex | 59 +++++++++++-------- mix.exs | 1 + mix.lock | 1 + priv/tracker/js/plausible.exclusions.hash.js | 1 + ...lausible.exclusions.hash.outbound-links.js | 1 + tracker/compile.js | 18 +++--- tracker/package-lock.json | 14 +++++ tracker/package.json | 1 + tracker/src/plausible.js | 14 ++--- 9 files changed, 71 insertions(+), 39 deletions(-) create mode 100644 priv/tracker/js/plausible.exclusions.hash.js create mode 100644 priv/tracker/js/plausible.exclusions.hash.outbound-links.js diff --git a/lib/plausible_web/plugs/tracker.ex b/lib/plausible_web/plugs/tracker.ex index 04e2b69f7742..b02d5976d2b0 100644 --- a/lib/plausible_web/plugs/tracker.ex +++ b/lib/plausible_web/plugs/tracker.ex @@ -2,30 +2,41 @@ defmodule PlausibleWeb.Tracker do import Plug.Conn use Agent - @templates [ - "plausible.js", - "plausible.exclusions.js", - "plausible.hash.js", - "plausible.outbound-links.js", - "plausible.hash.exclusions.js", - "plausible.hash.outbound-links.js", - "plausible.hash.exclusions.outbound-links.js", - "plausible.exclusions.outbound-links.js", - "p.js" - ] - @aliases %{ - "plausible.js" => ["analytics.js"], - "plausible.hash.outbound-links.js" => ["plausible.outbound-links.hash.js"], - "plausible.hash.exclusions.js" => ["plausible.exclusions.hash.js"], - "plausible.exclusions.outbound-links.js" => ["plausible.outbound-links.exclusions.js"], - "plausible.hash.exclusions.outbound-links.js" => [ - "plausible.exclusions.hash.outbound-links.js", - "plausible.exclusions.outbound-links.hash.js", - "plausible.hash.outbound-links.exclusions.js", - "plausible.outbound-links.hash.exclusions.js", - "plausible.outbound-links.exclusions.hash.js" - ] - } + base_variants = ["hash", "outbound-links", "exclusions"] + + # Generates Power Set of all variants + variants = + 1..Enum.count(base_variants) + |> Enum.map(fn x -> + Combination.combine(base_variants, x) + |> Enum.map(fn y -> Enum.sort(y) |> Enum.join(".") end) + end) + |> List.flatten() + + # Formats power set into filenames + files_available = + ["plausible.js", "p.js"] ++ Enum.map(variants, fn v -> "plausible.#{v}.js" end) + + # Computes permutations for every power set elements, formats them as alias filenames + aliases_available = + Enum.map(variants, fn x -> + variants = + String.split(x, ".") + |> Combination.permutate() + |> Enum.map(fn p -> Enum.join(p, ".") end) + |> Enum.filter(fn permutation -> permutation != x end) + |> Enum.map(fn v -> "plausible.#{v}.js" end) + + if Enum.count(variants) > 0 do + {"plausible.#{x}.js", variants} + end + end) + |> Enum.reject(fn x -> x == nil end) + |> Enum.into(%{}) + |> Map.put("plausible.js", ["analytics.js"]) + + @templates files_available + @aliases aliases_available #  1 hour @max_age 3600 diff --git a/mix.exs b/mix.exs index f6e3b9aef38f..932ad9369c71 100644 --- a/mix.exs +++ b/mix.exs @@ -51,6 +51,7 @@ defmodule Plausible.MixProject do defp deps do [ {:bcrypt_elixir, "~> 2.0"}, + {:combination, "~> 0.0.3"}, {:cors_plug, "~> 1.5"}, {:ecto_sql, "~> 3.0"}, {:elixir_uuid, "~> 1.2"}, diff --git a/mix.lock b/mix.lock index 2abdce41cb6d..73174ccdd931 100644 --- a/mix.lock +++ b/mix.lock @@ -14,6 +14,7 @@ "certifi": {:hex, :certifi, "2.6.1", "dbab8e5e155a0763eea978c913ca280a6b544bfa115633fa20249c3d396d9493", [:rebar3], [], "hexpm", "524c97b4991b3849dd5c17a631223896272c6b0af446778ba4675a1dff53bb7e"}, "clickhouse_ecto": {:git, "https://github.com/plausible/clickhouse_ecto.git", "1969f14ecef7c357b2bd8bdc3e566234269de58c", []}, "clickhousex": {:git, "https://github.com/plausible/clickhousex", "0832dd4b1af1f0eba1d1018c231bf0d8d281f031", []}, + "combination": {:hex, :combination, "0.0.3", "746aedca63d833293ec6e835aa1f34974868829b1486b1e1cb0685f0b2ae1f41", [:mix], [], "hexpm", "72b099f463df42ef7dc6371d250c7070b57b6c5902853f69deb894f79eda18ca"}, "combine": {:hex, :combine, "0.10.0", "eff8224eeb56498a2af13011d142c5e7997a80c8f5b97c499f84c841032e429f", [:mix], [], "hexpm", "1b1dbc1790073076580d0d1d64e42eae2366583e7aecd455d1215b0d16f2451b"}, "comeonin": {:hex, :comeonin, "5.3.2", "5c2f893d05c56ae3f5e24c1b983c2d5dfb88c6d979c9287a76a7feb1e1d8d646", [:mix], [], "hexpm", "d0993402844c49539aeadb3fe46a3c9bd190f1ecf86b6f9ebd71957534c95f04"}, "connection": {:hex, :connection, "1.0.4", "a1cae72211f0eef17705aaededacac3eb30e6625b04a6117c1b2db6ace7d5976", [:mix], [], "hexpm", "4a0850c9be22a43af9920a71ab17c051f5f7d45c209e40269a1938832510e4d9"}, diff --git a/priv/tracker/js/plausible.exclusions.hash.js b/priv/tracker/js/plausible.exclusions.hash.js new file mode 100644 index 000000000000..efa52f734c97 --- /dev/null +++ b/priv/tracker/js/plausible.exclusions.hash.js @@ -0,0 +1 @@ +!function(i,o){"use strict";var e,l=i.location,s=i.document,t=s.querySelector('[src*="'+o+'"]'),c=t&&t.getAttribute("data-domain"),p=i.localStorage.plausible_ignore,u=t&&t.getAttribute("data-exclude").split(",");function g(e){console.warn("Ignoring Event: "+e)}function a(e,t){if(/^localhost$|^127(?:\.[0-9]+){0,2}\.[0-9]+$|^(?:0*\:)*?:?0*1$/.test(l.hostname)||"file:"===l.protocol)return g("localhost");if(!(i.phantom||i._phantom||i.__nightmare||i.navigator.webdriver)){if("true"==p)return g("localStorage flag");if(u)for(var a=0;a"); \ No newline at end of file diff --git a/priv/tracker/js/plausible.exclusions.hash.outbound-links.js b/priv/tracker/js/plausible.exclusions.hash.outbound-links.js new file mode 100644 index 000000000000..3f854ae4a34a --- /dev/null +++ b/priv/tracker/js/plausible.exclusions.hash.outbound-links.js @@ -0,0 +1 @@ +!function(i,o){"use strict";var e,l=i.location,s=i.document,t=s.querySelector('[src*="'+o+'"]'),c=t&&t.getAttribute("data-domain"),p=i.localStorage.plausible_ignore,u=t&&t.getAttribute("data-exclude").split(",");function h(e){console.warn("Ignoring Event: "+e)}function a(e,t){if(/^localhost$|^127(?:\.[0-9]+){0,2}\.[0-9]+$|^(?:0*\:)*?:?0*1$/.test(l.hostname)||"file:"===l.protocol)return h("localhost");if(!(i.phantom||i._phantom||i.__nightmare||i.navigator.webdriver)){if("true"==p)return h("localStorage flag");if(u)for(var a=0;a"); \ No newline at end of file diff --git a/tracker/compile.js b/tracker/compile.js index e33ba321d862..7f67804f4b12 100644 --- a/tracker/compile.js +++ b/tracker/compile.js @@ -2,6 +2,7 @@ const uglify = require("uglify-js"); const fs = require('fs') const path = require('path') const Handlebars = require("handlebars"); +const g = require("generatorics"); function relPath(segment) { return path.join(__dirname, segment) @@ -15,13 +16,14 @@ function compilefile(input, output, templateVars = {}) { fs.writeFileSync(output, result.code) } +const base_variants = ["hash", "outbound-links", "exclusions"] +const variants = [...g.clone.powerSet(base_variants)].filter(a => a.length > 0).map(a => a.sort()); + compilefile(relPath('src/plausible.js'), relPath('../priv/tracker/js/plausible.js')) -compilefile(relPath('src/plausible.js'), relPath('../priv/tracker/js/plausible.exclusions.js'), {exclusionMode: true}) -compilefile(relPath('src/plausible.js'), relPath('../priv/tracker/js/plausible.hash.js'), {hashMode: true}) -compilefile(relPath('src/plausible.js'), relPath('../priv/tracker/js/plausible.hash.exclusions.js'), {hashMode: true, exclusionMode: true}) -compilefile(relPath('src/plausible.js'), relPath('../priv/tracker/js/plausible.outbound-links.js'), {outboundLinks: true}) -compilefile(relPath('src/plausible.js'), relPath('../priv/tracker/js/plausible.exclusions.outbound-links.js'), {outboundLinks: true, exclusionMode: true}) -compilefile(relPath('src/plausible.js'), relPath('../priv/tracker/js/plausible.hash.outbound-links.js'), {hashMode: true, outboundLinks: true}) -compilefile(relPath('src/plausible.js'), relPath('../priv/tracker/js/plausible.hash.exclusions.outbound-links.js'), {hashMode: true, outboundLinks: true, exclusionMode: true}) +compilefile(relPath('src/plausible.js'), relPath('../priv/tracker/js/analytics.js')) compilefile(relPath('src/p.js'), relPath('../priv/tracker/js/p.js')) -fs.copyFileSync(relPath('../priv/tracker/js/plausible.js'), relPath('../priv/tracker/js/analytics.js')) + +variants.map(variant => { + const options = variant.map(variant => variant.replace('-', '_')).reduce((acc, curr) => (acc[curr] = true, acc), {}) + compilefile(relPath('src/plausible.js'), relPath(`../priv/tracker/js/plausible.${variant.join('.')}.js`), options) +}) diff --git a/tracker/package-lock.json b/tracker/package-lock.json index cb50639fb8af..f75c6ff886ca 100644 --- a/tracker/package-lock.json +++ b/tracker/package-lock.json @@ -6,6 +6,7 @@ "": { "license": "MIT", "dependencies": { + "generatorics": "^1.1.0", "handlebars": "^4.7.7", "uglify-js": "^3.9.4" } @@ -15,6 +16,14 @@ "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" }, + "node_modules/generatorics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/generatorics/-/generatorics-1.1.0.tgz", + "integrity": "sha1-aVBgu42IuQmzAXGlyz1CR2hmETg=", + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/handlebars": { "version": "4.7.7", "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz", @@ -79,6 +88,11 @@ "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" }, + "generatorics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/generatorics/-/generatorics-1.1.0.tgz", + "integrity": "sha1-aVBgu42IuQmzAXGlyz1CR2hmETg=" + }, "handlebars": { "version": "4.7.7", "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz", diff --git a/tracker/package.json b/tracker/package.json index 46c3a9c60163..88ce3cb434d0 100644 --- a/tracker/package.json +++ b/tracker/package.json @@ -4,6 +4,7 @@ }, "license": "MIT", "dependencies": { + "generatorics": "^1.1.0", "handlebars": "^4.7.7", "uglify-js": "^3.9.4" } diff --git a/tracker/src/plausible.js b/tracker/src/plausible.js index aff85ede580c..ffb6fa644309 100644 --- a/tracker/src/plausible.js +++ b/tracker/src/plausible.js @@ -7,7 +7,7 @@ var scriptEl = document.querySelector('[src*="' + plausibleHost +'"]') var domain = scriptEl && scriptEl.getAttribute('data-domain') var plausible_ignore = window.localStorage.plausible_ignore; - {{#if exclusionMode}} + {{#if exclusions}} var excludedPaths = scriptEl && scriptEl.getAttribute('data-exclude').split(','); {{/if}} var lastPage; @@ -20,7 +20,7 @@ if (/^localhost$|^127(?:\.[0-9]+){0,2}\.[0-9]+$|^(?:0*\:)*?:?0*1$/.test(location.hostname) || location.protocol === 'file:') return warn('localhost'); if (window.phantom || window._phantom || window.__nightmare || window.navigator.webdriver || window.Cypress) return; if (plausible_ignore=="true") return warn('localStorage flag') - {{#if exclusionMode}} + {{#if exclusions}} if (excludedPaths) for (var i = 0; i < excludedPaths.length; i++) if (eventName == "pageview" && location.pathname.match(new RegExp('^' + excludedPaths[i].trim().replace(/\*\*/g, '.*').replace(/([^\.])\*/g, '$1[^\\s\/]*') + '\/?$'))) @@ -39,7 +39,7 @@ if (options && options.props) { payload.p = JSON.stringify(options.props) } - {{#if hashMode}} + {{#if hash}} payload.h = 1 {{/if}} @@ -57,7 +57,7 @@ } function page() { - {{#unless hashMode}} + {{#unless hash}} if (lastPage === location.pathname) return; {{/unless}} lastPage = location.pathname @@ -70,7 +70,7 @@ } } - {{#if outboundLinks}} + {{#if outbound_links}} function handleOutbound(event) { var link = event.target; var middle = event.type == "auxclick" && event.which == 2; @@ -102,7 +102,7 @@ {{/if}} try { - {{#if hashMode}} + {{#if hash}} window.addEventListener('hashchange', page) {{else}} var his = window.history @@ -116,7 +116,7 @@ } {{/if}} - {{#if outboundLinks}} + {{#if outbound_links}} registerOutboundLinkEvents() {{/if}}