UNPKG

3.46 kBJavaScriptView Raw
1const path = require('path')
2const defaults = require('./defaults')
3
4// doNotTrack polyfill
5// https://gist.github.com/pi0/a76fd97c4ea259c89f728a4a8ebca741
6const dnt = "(function(w,n,d,m,e,p){w[d]=(w[d]==1||n[d]=='yes'||n[d]==1||n[m]==1||(w[e]&&w[e].p&&e[e][p]()))?1:0})(window,'navigator','doNotTrack','msDoNotTrack','external','msTrackingProtectionEnabled')"
7
8module.exports = async function gtmModule (_options) {
9 const options = {
10 ...defaults,
11 ..._options,
12 ...this.options.gtm
13 }
14
15 // Don't include when run in dev mode unless dev: true is configured
16 if (this.options.dev && !options.dev) {
17 return
18 }
19
20 // Async id evaluation
21 if (typeof (options.id) === 'function') {
22 options.id = await options.id()
23 }
24
25 // Build query
26 const query = {
27 // Default is dataLayer for google
28 l: options.layer !== 'dataLayer' ? options.layer : null,
29 ...options.variables
30 }
31 const queryString = Object.keys(query)
32 .filter(key => query[key] !== null && query[key] !== undefined)
33 .map(key => `${encodeURIComponent(key)}=${encodeURIComponent(query[key])}`)
34 .join('&')
35
36 // Compile scripts
37 const initLayer = "w[l]=w[l]||[];w[l].push({'gtm.start':new Date().getTime(),event:'gtm.js'})" // deps: w,l
38
39 const injectScript = `var f=d.getElementsByTagName(s)[0],j=d.createElement(s);j.${options.scriptDefer ? 'defer' : 'async'}=true;j.src='${options.scriptURL + '?id=\'+i' + (queryString ? (`+'&${queryString}` + '\'') : '')};f.parentNode.insertBefore(j,f)` // deps: d,s,i
40
41 let script = `${initLayer};w[x]={};w._gtm_inject=function(i){if(w.doNotTrack||w[x][i])return;w[x][i]=1;${injectScript};}`
42
43 if (options.autoInit) {
44 if (options.id) {
45 script += `;w[y]('${options.id}')`
46 } else {
47 // eslint-disable-next-line no-console
48 console.warn('[@nuxtjs/gtm] `autoInit` set but no id provided!')
49 }
50 }
51
52 // Add doNotTrack polyfill and wrap to IIFE
53 script = `${dnt};(function(w,d,s,l,x,y){${script}})(window,document,'script','${options.layer}','_gtm_ids','_gtm_inject')`
54
55 // Guard against double IIFE executation in SPA mode (#3)
56 script = `if(!window._gtm_init){window._gtm_init=1;${script}}`
57
58 // Add google tag manager <script> to head
59 this.options.head.script = this.options.head.script || []
60 this.options.head.script.push({
61 hid: options.scriptId,
62 innerHTML: script
63 })
64
65 // Prepend google tag manager <noscript> fallback to <body>
66 const renderIframe = id => `<iframe src="${options.noscriptURL + '?id=' + id + '&' + queryString}" height="0" width="0" style="display:none;visibility:hidden" title="gtm"></iframe>`
67 if (options.noscript && options.id) {
68 this.options.head.noscript = this.options.head.noscript || []
69 this.options.head.noscript.push({
70 hid: options.noscriptId,
71 pbody: true,
72 innerHTML: options.id ? renderIframe(options.id) : '' /* placeholder for SSR calls */
73 })
74 }
75
76 // Disable sanitazions
77 this.options.head.__dangerouslyDisableSanitizersByTagID = this.options.head.__dangerouslyDisableSanitizersByTagID || {}
78 this.options.head.__dangerouslyDisableSanitizersByTagID[options.scriptId] = ['innerHTML']
79 this.options.head.__dangerouslyDisableSanitizersByTagID[options.noscriptId] = ['innerHTML']
80
81 // Register plugin
82 this.addPlugin({
83 src: path.resolve(__dirname, 'plugin.js'),
84 fileName: 'gtm.js',
85 options: {
86 ...options,
87 renderIframe
88 }
89 })
90}
91
92module.exports.meta = require('../package.json')