Skip to content

Commit

Permalink
refactor(analytics): GA analytics tracker from ENV variable, move ana…
Browse files Browse the repository at this point in the history
…lytics logic into background pa

Based on process.env.NODE_ENV either GA_TRACKER_DEV or GA_TRACKER_PROD is loaded from .evn file.
Also moved the analytics from template appending mechanism to background page because of clashes
with host site GA. More details in SO answer
https://stackoverflow.com/questions/10285886/chrome-extension-adding-external-javascript-to-current-pages-html?answertab=active#tab-top

Closes realreality#52
  • Loading branch information
vire committed Jun 25, 2017
1 parent 249e6ce commit 7c6b6c8
Show file tree
Hide file tree
Showing 10 changed files with 162 additions and 122 deletions.
34 changes: 19 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,25 +25,33 @@ Original idea was that Real Reality will be webpage where you can see mashup of
1. `git commit -m "my new great addition!"`
1. `git push`

Final extension structure
```bash
build
├── _locales
├── background.bundle.js
├── contentscript.bundle.js
├── css
├── fonts
├── images
└── manifest.json
```

### Environment variables

This project supports [dotenv](https://www.npmjs.com/package/dotenv) variables, by creating a `.env` file, you can put your secrets there. All `env` variables are then available in `./config/env.js` where you can export them and use in webpack `DefinePlugin` in `webpack.conf.js`

List of currently used environment variables within project

* `GA_TRACKER_DEV` - Google Analytics TRACKER ID user in non-production builds
* `GA_TRACKER_PROD` - GA TRACKER ID for production
* `GMAPS_API_KEY` - user your own please
* `IPR_REST_API` - endpoint for real-reality


### Building

to compile a **production** version of the extension into \<project-root\>/**build** folder run

```
yarn build
```

or if you wanna specify custom GA
```
GA_TRACKER_PROD=GA-XXXXX-X yarn build
```


Quick and dirty [source code of IPR Data Rest API Server](https://github.com/bedla/praguehacks-realreality).

Main script is in **./src/js/contentscript.js**
Expand All @@ -57,7 +65,3 @@ IPR API is backed by [IPR Data Rest API Server](https://github.com/realreality/r
[Open Society Fund Praha / Fond Otakara Motejla](http://www.otevrenadata.cz/) for their [open data](https://en.wikipedia.org/wiki/Open_data) activities (like organizing Prague Hacks hackathon and other similar events, propagation the open data idea in goverment institutions..etc.).

Samuel Simões - this extension is built on top of the scaffold [chrome-extension-webpack-boilerplate](https://github.com/samuelsimoes/chrome-extension-webpack-boilerplate)




17 changes: 10 additions & 7 deletions config/env.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
// tiny wrapper with default env vars
const env = require('dotenv');
const dotenv = require('dotenv')

env.load();
dotenv.load()

const env = process.env

module.exports = {

PORT: (process.env.PORT || 3000),
GMAPS_API_KEY: process.env.GMAPS_API_KEY,
IPR_REST_API: (process.env.IPR_REST_API || 'https://realreality.publicstaticvoidmain.cz/rest')
};
GA_TRACKER_DEV: env.GA_TRACKER_DEV,
GA_TRACKER_PROD: env.GA_TRACKER_PROD,
PORT: (env.PORT || 3000),
GMAPS_API_KEY: env.GMAPS_API_KEY,
IPR_REST_API: (env.IPR_REST_API || 'https://realreality.publicstaticvoidmain.cz/rest'),
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"private": true,
"scripts": {
"cleanup": "rm -rf build",
"build": "npm run cleanup && node scripts/build-manifest.js && webpack -p",
"build": "node scripts/build-manifest.js && webpack --env=prod -p",
"cz": "git-cz",
"commitmsg": "validate-commit-msg",
"lint": "eslint -c .eslintrc ./src/",
Expand Down
2 changes: 1 addition & 1 deletion scripts/webserver.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ const webpack = require('webpack')
const path = require('path')
const WriteFilePlugin = require('write-file-webpack-plugin')

const config = require('../webpack.config')
const config = require('../webpack.config')('dev')
const env = require('./../config/env')

// setup manifest
Expand Down
23 changes: 21 additions & 2 deletions src/js/background.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,18 @@

const debugAnalytics = process.env.GA_DEBUG === 'enabled' ? '_debug' : ''
const analyticsURL = `https://www.google-analytics.com/analytics${debugAnalytics}.js`

;(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', analyticsURL, 'ga')

window.ga('create', process.env.GA_TRACKER_ID, 'auto')
window.ga('set', 'checkProtocolTask', function(){ /* nothing */ })
/**
* Code that detects host page and switches icons in toolbar.
*/
chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
console.log('request', request)
if (request.switchIconOn) {
chrome.browserAction.setIcon({
path: {
Expand All @@ -12,4 +22,13 @@ chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
tabId: sender.tab.id,
})
}
})

if(request.eventType === 'EXTENSION_INIT') {
window.ga('send', {
hitType: 'pageview',
location: request.locationHref,
page: request.locationPathName,
title: request.documentTitle,
})
}
})
17 changes: 10 additions & 7 deletions src/js/contentscript.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,10 @@ import { streetNamePredicate, addStyles } from './utils'

import '../css/cssnormalize.scss'
import '../css/panel.scss'
import panelTemplate from 'html-loader!../templates/panel.html'

import App from './components/App.vue'

Vue.use(VueI18n)
Vue.use(VueI18n)
RR.logInfo('contentscript loaded')

chrome.runtime.sendMessage({ 'switchIconOn': true })
Expand All @@ -25,7 +24,7 @@ const initVueTranslations = () => {
const [appLanguage] = languages
RR.logDebug('Detected accepted languages: ', languages)
RR.logInfo('Selected app language: ', appLanguage)

const vueI18n = new VueI18n({
locale: appLanguage,
fallbackLocale: 'en',
Expand All @@ -43,11 +42,15 @@ const initVueTranslations = () => {

const loadPanel = function(address) {
RR.logDebug('Injecting panel (template) to page')
// html from panelTemplate holds the entry-point `#reality-panel-root`
$('body').append(panelTemplate)

RR.logDebug('Initializing view (replacing values in panel.html template)')

$('body').append('<div id="reality-panel-root"></div>')
chrome.runtime.sendMessage({
eventType: 'EXTENSION_INIT',
documentTitle: document.title,
locationHost: window.location.host,
locationHref: window.location.href,
locationPathName: window.location.pathname,
})
initVueTranslations()
.then((i18n) => {
Vue.config.devtools = true // does not work in extension
Expand Down
8 changes: 6 additions & 2 deletions src/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
"*://reality.idnes.cz/*"
],
"js": [
"vendor.bundle.js",
"contentscript.bundle.js"
],
"run_at": "document_end",
Expand All @@ -48,7 +49,10 @@
"default_popup": "popup.html"
},
"background": {
"scripts": ["background.bundle.js"]
"scripts": [
"vendor.bundle.js",
"background.bundle.js"
]
},
"content_security_policy": "script-src 'self' https://maps.googleapis.com; 'unsafe-eval' http://localhost:%PORT%; object-src 'self'"
"content_security_policy": "script-src 'self' https://maps.googleapis.com https://www.google-analytics.com http://localhost:%PORT%; object-src 'self'"
}
20 changes: 0 additions & 20 deletions src/templates/panel.html

This file was deleted.

151 changes: 84 additions & 67 deletions webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,74 +10,91 @@ const webpack = require('webpack')
const env = require('./config/env')
const basePath = fileName => path.join(__dirname, 'src', 'js', fileName)

module.exports = {
entry: {
background: basePath('background.js'),
contentscript: basePath('contentscript.js'),
popup: basePath('popup.js'),
},
output: {
path: path.join(__dirname, 'build'),
filename: '[name].bundle.js',
},
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader',
},
{
enforce: 'pre',
test: /\.js$/,
exclude: /node_modules/,
loader: 'eslint-loader',
},
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
},
{
test: /\.scss$/,
loader: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: ['css-loader', 'postcss-loader'],
}),
},
module.exports = (profile) => {
const isProd = profile === 'prod'
const GA_TRACKER_ID = isProd ? env.GA_TRACKER_PROD : env.GA_TRACKER_DEV

return {
entry: {
background: basePath('background.js'),
contentscript: basePath('contentscript.js'),
popup: basePath('popup.js'),
},
output: {
path: path.join(__dirname, 'build'),
filename: '[name].bundle.js',
},
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader',
},
{
enforce: 'pre',
test: /\.js$/,
exclude: /node_modules/,
loader: 'eslint-loader',
},
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
},
{
test: /\.scss$/,
loader: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: ['css-loader', 'postcss-loader'],
}),
},
],
},
plugins: [
new ProgressBarPlugin(),
new webpack.LoaderOptionsPlugin({
options: {
postcss: [autoprefixer, precss],
excludeEntriesToHotReload: ['contentscript'], // a non-standard webpack opt, see usage in `./scripts/webserver.js`
},
}),
// expose and write the allowed env vars on the compiled bundle
new webpack.DefinePlugin({
'process.env': {
GMAPS_API_KEY: JSON.stringify(env.GMAPS_API_KEY),
GA_DEBUG: JSON.stringify(isProd ? 'disabled': 'enabled'),
GA_TRACKER_ID: JSON.stringify(GA_TRACKER_ID),
IPR_REST_API: JSON.stringify(env.IPR_REST_API),
},
}),
new HtmlWebpackPlugin({
template: path.join(__dirname, 'src', 'popup.html'),
filename: 'popup.html',
chunks: ['popup'],
}),
new CopyWebpackPlugin([
{ from: path.join(__dirname, 'src/_locales'), to: '_locales'},
{ from: path.join(__dirname, 'src/images'), to: 'images'},
{ from: path.join(__dirname, 'node_modules/font-awesome/css/font-awesome.css'), to: 'css'},
{ from: path.join(__dirname, 'node_modules/font-awesome/fonts'), to: 'fonts'},
]),
new ExtractTextPlugin('./css/panel.css'),
new webpack.LoaderOptionsPlugin({
debug: false,
minimize: true,
}),
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
minChunks: function(module){
return module.context && module.context.indexOf('node_modules') !== -1
},
}),

],
},
plugins: [
new ProgressBarPlugin(),
new webpack.LoaderOptionsPlugin({
options: {
postcss: [autoprefixer, precss],
excludeEntriesToHotReload: ['contentscript'], // a non-standard webpack opt, see usage in `./scripts/webserver.js`
},
}),
// expose and write the allowed env vars on the compiled bundle
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify(process.env.NODE_ENV || 'development'),
GMAPS_API_KEY: JSON.stringify(env.GMAPS_API_KEY),
IPR_REST_API: JSON.stringify(env.IPR_REST_API),
resolve: {
alias: {
'vue$': 'vue/dist/vue.esm.js',
},
}),
new HtmlWebpackPlugin({
template: path.join(__dirname, 'src', 'popup.html'),
filename: 'popup.html',
chunks: ['popup'],
}),
new CopyWebpackPlugin([
{ from: path.join(__dirname, 'src/_locales'), to: '_locales'},
{ from: path.join(__dirname, 'src/images'), to: 'images'},
{ from: path.join(__dirname, 'node_modules/font-awesome/css/font-awesome.css'), to: 'css'},
{ from: path.join(__dirname, 'node_modules/font-awesome/fonts'), to: 'fonts'},
]),
new ExtractTextPlugin('./css/panel.css'),
],
resolve: {
alias: {
'vue$': 'vue/dist/vue.common.js',
},
},
}
}
10 changes: 10 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3596,6 +3596,10 @@ load-json-file@^1.0.0:
pinkie-promise "^2.0.0"
strip-bom "^2.0.0"

load-script@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/load-script/-/load-script-1.0.0.tgz#0491939e0bee5643ee494a7e3da3d2bac70c6ca4"

loader-fs-cache@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/loader-fs-cache/-/loader-fs-cache-1.0.1.tgz#56e0bf08bd9708b26a765b68509840c8dec9fdbc"
Expand Down Expand Up @@ -5997,6 +6001,12 @@ void-elements@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-2.0.1.tgz#c066afb582bb1cb4128d60ea92392e94d5e9dbec"

vue-analytics@4.1.2:
version "4.1.2"
resolved "https://registry.yarnpkg.com/vue-analytics/-/vue-analytics-4.1.2.tgz#ea8be43810e3505c668f9b114fa5451baa435877"
dependencies:
load-script "^1.0.0"

vue-class-component@^5.0.0:
version "5.0.1"
resolved "https://registry.yarnpkg.com/vue-class-component/-/vue-class-component-5.0.1.tgz#feda06c3da266cee9064e224ba491e089923dce8"
Expand Down

0 comments on commit 7c6b6c8

Please sign in to comment.