-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit ed2abec
Showing
19 changed files
with
8,780 additions
and
0 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
node_modules | ||
npm-debug.log | ||
.DS_Store |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
# Google Analytics Task Manager | ||
|
||
This guide explains what the `gaTaskManager` plugin is and how to integrate it into your `analytics.js` tracking implementation. | ||
|
||
## Overview | ||
|
||
Google Analytics [Tasks](https://developers.google.com/analytics/devguides/collection/analyticsjs/tasks) is "an advanced feature used to customize how analytics.js validates, constructs, and sends measurement protocol requests". `gaTaskManager` is a Google Analytics plugin which expands analytics.js Tasks, allowing the user to specify multiple functions to be run for each GA Task. Also provides utility functions to add common functions to tasks, such as setting Custom Dimensions. If you want to be able to run multiple functions for one or more Tasks included in the measurement protocol's request lifecycle, this is the plugin for you. | ||
|
||
## Usage | ||
|
||
To enable the `gaTaskManager` plugin, run the [`require`](https://developers.google.com/analytics/devguides/collection/analyticsjs/using-plugins) command, specify the plugin name `'gaTaskManager'`: | ||
|
||
```js | ||
ga('require', 'gaTaskManager'); | ||
``` | ||
|
||
When you require the `gaTaskManager` plugin, its constructor overrides the GA tracker's Tasks' function with its own, and sets the original Task function as the first function to be run for that respective Task. From an output perspective, nothing changes by requiring the plugin, it simply bootstraps the tracker so that you're able to use the methods listed below. | ||
|
||
## Methods | ||
|
||
The following table lists all methods for the `gaTaskManager` plugin: | ||
|
||
<table> | ||
<tr valign="top"> | ||
<th align="left">Name</th> | ||
<th align="left">Description</th> | ||
</tr> | ||
<tr valign="top"> | ||
<td><code>addFunctionToTask</code></td> | ||
<td>Adds a function to be executed at the specified GA Task. Can be used to add to any Task listed at https://developers.google.com/analytics/devguides/collection/analyticsjs/tasks</td> | ||
</tr> | ||
<tr valign="top"> | ||
<td><code>setCustomDimension</code></td> | ||
<td>Adds a function which sets a GA Custom Dimension at the specified GA Task execution time. Defaults to execution on the <code>customTask</code> Task</td> | ||
</tr> | ||
<tr valign="top"> | ||
<td><code>remove</code></td> | ||
<td>Removes the <code>gaTaskManager</code> plugin from the specified tracker, restoring all original functions set to each Task prior to the plugin being required.</td> | ||
</tr> | ||
</table> | ||
|
||
For details on how `analytics.js` plugin methods work and how to invoke them, see [calling plugin methods](https://developers.google.com/analytics/devguides/collection/analyticsjs/using-plugins#calling_plugin_methods) in the `analytics.js` documentation. | ||
|
||
## Examples | ||
|
||
### Setting a Custom Dimension at every hit: | ||
|
||
This example sets a Custom Dimension `dimension2` at every Hit: | ||
|
||
```js | ||
var index = 1; | ||
ga('gaTaskManager:setCustomDimension', index, 'foo'); | ||
|
||
``` | ||
|
||
### Setting Custom Dimension value just-in-time: | ||
|
||
This example delegates the generation of the value for the Custom Dimension to a function that returns the current timestamp at every Hit: | ||
|
||
```js | ||
var index = 2; | ||
ga('gaTaskManager:setCustomDimension', index, function(){ | ||
return Date.now() / 1000 | 0; | ||
}); | ||
|
||
``` | ||
|
||
### Executing an arbitrary function on a Task | ||
|
||
This example adds an arbitrary function to be executed after sending the normal request to | ||
request to www.google-analytics.com/collect. | ||
|
||
```js | ||
ga('gaTaskManager:addFunctionToTask', function(model) { | ||
// Send a copy of the request to a local server | ||
var xhr = new XMLHttpRequest(); | ||
xhr.open('POST', '/localhits', true); | ||
xhr.send(model.get('hitPayload')); | ||
}); | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
/** | ||
* Copyright 2017 Google Inc. All Rights Reserved. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
|
||
/* eslint-env node */ | ||
/* eslint require-jsdoc: "off" */ | ||
|
||
|
||
const fs = require('fs-extra'); | ||
const glob = require('glob'); | ||
const {compile}= require('google-closure-compiler-js'); | ||
const {rollup} = require('rollup'); | ||
const memory = require('rollup-plugin-memory'); | ||
const nodeResolve = require('rollup-plugin-node-resolve'); | ||
const path = require('path'); | ||
const {SourceMapGenerator, SourceMapConsumer} = require('source-map'); | ||
|
||
|
||
module.exports = (output) => { | ||
const entry = path.resolve(__dirname, '../lib/index.js'); | ||
const plugins = [nodeResolve()]; | ||
return new Promise((resolve, reject) => { | ||
rollup({entry, plugins}).then((bundle) => { | ||
try { | ||
const rollupResult = bundle.generate({ | ||
format: 'es', | ||
dest: output, | ||
sourceMap: true, | ||
}); | ||
|
||
const externsDir = path.resolve(__dirname, '../lib/externs'); | ||
const externs = glob.sync(path.join(externsDir, '*.js')) | ||
.reduce((acc, cur) => acc + fs.readFileSync(cur, 'utf-8'), ''); | ||
|
||
|
||
const closureFlags = { | ||
jsCode: [{ | ||
src: rollupResult.code, | ||
path: path.basename(output), | ||
}], | ||
compilationLevel: 'ADVANCED', | ||
useTypesForOptimization: true, | ||
outputWrapper: | ||
'(function(){%output%})();\n' + | ||
`//# sourceMappingURL=${path.basename(output)}.map`, | ||
assumeFunctionWrapper: true, | ||
rewritePolyfills: false, | ||
warningLevel: 'VERBOSE', | ||
createSourceMap: true, | ||
externs: [{src: externs}], | ||
}; | ||
|
||
const closureResult = compile(closureFlags); | ||
if (closureResult.errors.length || closureResult.warnings.length) { | ||
const rollupMap = new SourceMapConsumer(rollupResult.map); | ||
|
||
// Remap errors from the closure compiler output to the original | ||
// files before rollup bundled them. | ||
const remap = (type) => (item) => { | ||
let {line, column, source} = rollupMap.originalPositionFor({ | ||
line: item.lineNo, | ||
column: item.charNo, | ||
}); | ||
source = path.relative('.', path.resolve(__dirname, '..', source)); | ||
return {type, line, column, source, desc: item.description}; | ||
}; | ||
|
||
|
||
reject({ | ||
errors: [ | ||
...closureResult.errors.map(remap('error')), | ||
...closureResult.warnings.map(remap('warning')), | ||
], | ||
}); | ||
} else { | ||
// Currently, closure compiler doesn't support applying its generated | ||
// source map to an existing source map, so we do it manually. | ||
const fromMap = JSON.parse(closureResult.sourceMap); | ||
const toMap = rollupResult.map; | ||
|
||
const generator = SourceMapGenerator.fromSourceMap( | ||
new SourceMapConsumer(fromMap)); | ||
|
||
generator.applySourceMap( | ||
new SourceMapConsumer(toMap), path.basename(output)); | ||
|
||
const sourceMap = generator.toString(); | ||
|
||
resolve({ | ||
code: closureResult.compiledCode, | ||
map: sourceMap, | ||
}); | ||
} | ||
} catch(err) { | ||
reject(err); | ||
} | ||
}).catch(reject); | ||
}); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
/** | ||
* Copyright 2017 Google Inc. All Rights Reserved. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
|
||
const chalk = require('chalk'); | ||
|
||
|
||
const log = (msg) => process.stderr.write(msg); | ||
|
||
|
||
module.exports = (err) => { | ||
if (err instanceof Error) { | ||
log(`\n${err.stack}\n`); | ||
} else { | ||
log('\n'); | ||
for (let {source, line, column, desc, type} of err.errors) { | ||
const color = chalk[type == 'error' ? 'red' : 'yellow']; | ||
|
||
log(`${color(`[${type}]`)} ${desc}\n`); | ||
log(chalk.gray(`${source} [${line}:${column}]\n\n`)); | ||
} | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
#!/usr/bin/env node | ||
/* eslint no-console: "off" */ | ||
|
||
|
||
const chalk = require('chalk'); | ||
const fs = require('fs-extra'); | ||
const gzipSize = require('gzip-size'); | ||
const minimist = require('minimist'); | ||
const path = require('path'); | ||
const build = require('./build'); | ||
const logErrors = require('./errors'); | ||
|
||
const output = 'ga-task-manager.js'; | ||
const {cyan, gray, green, red} = chalk; | ||
|
||
build(output) | ||
.then(({code, map}) => { | ||
fs.outputFileSync(output, code, 'utf-8'); | ||
fs.outputFileSync(`${output}.map`, map, 'utf-8'); | ||
|
||
const size = (gzipSize.sync(code) / 1000).toFixed(1); | ||
|
||
console.log(green(`\nGreat success!\n`)); | ||
console.log(cyan('Built: ') + | ||
`${output} ${gray(`(${size} Kb gzipped)`)}`); | ||
console.log(cyan('Built: ') + | ||
`${output}.map\n`); | ||
}) | ||
.catch(logErrors) | ||
.catch(console.error.bind(console)); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
/** | ||
* Copyright 2016 Google Inc. All Rights Reserved. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
* | ||
* Modifications Copyright (C) 2017 Anki, Inc. | ||
*/ | ||
|
||
|
||
import express from 'express'; | ||
import serveStatic from 'serve-static'; | ||
|
||
|
||
let server; | ||
|
||
|
||
/** | ||
* Starts the express log server. | ||
* @param {Function} done A callback to invoke once the server is up. | ||
*/ | ||
export function start(done) { | ||
const app = express(); | ||
app.use(serveStatic('./')); | ||
server = app.listen(8080, done); | ||
} | ||
|
||
/** | ||
* Stops the log server and deletes the logs. | ||
*/ | ||
export function stop() { | ||
server.close(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
|
||
Usage: ga-task-manager | ||
|
||
Generates a minified, ga-task-manager file and source map. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
<!doctype html> | ||
<html> | ||
<head> | ||
<script> | ||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ | ||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), | ||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) | ||
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga'); | ||
|
||
// Anki Test Property | ||
ga('create', 'UA-40941061-3', 'auto'); | ||
|
||
// Require the plugin | ||
ga('require', 'gaTaskManager'); | ||
|
||
// Add a function to customTask | ||
ga('gaTaskManager:addFunctionToTask', 'customTask', 'logShinyString', function(model){ | ||
console.log("Look at my shiny new random customTask"); | ||
}); | ||
|
||
// Add a second function to customTask | ||
ga('gaTaskManager:addFunctionToTask', 'customTask', 'logShinyStringAgain', function(model){ | ||
console.log("Look at my shiny second random customTask which will be executed after the first!"); | ||
}); | ||
|
||
// Set Dimensions with a static string value | ||
ga('gaTaskManager:setCustomDimension', 1, 14) | ||
|
||
// Set Dimensions with function to return the value at time of execution | ||
ga('gaTaskManager:setCustomDimension', 2, function(){return Date.now() / 1000 | 0}) | ||
|
||
ga('send', 'pageview'); | ||
</script> | ||
<script async src="/ga-task-manager.js"></script> | ||
</head> | ||
<body> | ||
</body> | ||
</html> |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Oops, something went wrong.