Skip to content

Commit e21a80d

Browse files
authored
feat: use Google Tag Manager gtm.js in addition to gtag.js (#189)
1 parent 5f901d0 commit e21a80d

File tree

2 files changed

+65
-30
lines changed

2 files changed

+65
-30
lines changed

.vitepress/config.ts

Lines changed: 62 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,21 @@ import { defaultGroupLink, sidebarLinks } from '../docs/links';
66

77
dotenv.config();
88

9-
const BASE = '/';
10-
const BASE_WITH_ORIGIN = `https://developer.stackblitz.com${BASE}`;
9+
const BASE_PATH = '/';
10+
const BASE_WITH_ORIGIN = `https://developer.stackblitz.com${BASE_PATH}`;
1111

1212
interface ThemeConfig extends DefaultTheme.Config {
1313
chatlio: {
14-
id: string | undefined,
15-
allowedRoutes: (RegExp|string)[],
16-
}
14+
id: string | undefined;
15+
allowedRoutes: (RegExp | string)[];
16+
};
1717
}
1818

1919
export default defineConfigWithTheme<ThemeConfig>({
2020
srcDir: './docs',
21-
outDir: `./build${BASE}`,
21+
outDir: `./build${BASE_PATH}`,
2222
assetsDir: 'assets',
23-
base: BASE,
23+
base: BASE_PATH,
2424

2525
// Generate files as `/path/to/page.html` and URLs as `/path/to/page`
2626
cleanUrls: true,
@@ -34,7 +34,7 @@ export default defineConfigWithTheme<ThemeConfig>({
3434
description:
3535
'Discover how to use StackBlitz, an online development environment for frontend, Node.js and the JavaScript ecosystem.',
3636
head: [
37-
['link', { rel: 'icon', type: 'image/png', href: `${BASE}img/theme/favicon.png` }],
37+
['link', { rel: 'icon', type: 'image/png', href: `${BASE_PATH}img/theme/favicon.png` }],
3838
...getAnalyticsTags(process.env),
3939
],
4040

@@ -103,9 +103,9 @@ export default defineConfigWithTheme<ThemeConfig>({
103103
'/enterprise/': sidebarLinks('enterprise', ['enterprise']),
104104
},
105105
chatlio: {
106-
allowedRoutes: [`^${BASE}teams/.*`, `^${BASE}enterprise/.*`],
106+
allowedRoutes: [`^${BASE_PATH}teams/.*`, `^${BASE_PATH}enterprise/.*`],
107107
id: process.env.VITE_CHATLIO_ID,
108-
}
108+
},
109109
},
110110

111111
postRender(context) {
@@ -122,31 +122,64 @@ export default defineConfigWithTheme<ThemeConfig>({
122122
template: {
123123
compilerOptions: {
124124
isCustomElement: (tag) => {
125-
return ["chatlio-widget"].includes(tag.toLowerCase());
126-
}
127-
}
128-
}
125+
return ['chatlio-widget'].includes(tag.toLowerCase());
126+
},
127+
},
128+
},
129129
},
130130
});
131131

132-
function getAnalyticsTags(env: NodeJS.ProcessEnv): HeadConfig[] {
133-
if (!env.VITE_GTAG_ID) {
134-
return [];
132+
function getAnalyticsTags({
133+
VITE_GTM_ID = '',
134+
VITE_GTAG_ID = '',
135+
}: NodeJS.ProcessEnv): HeadConfig[] {
136+
// Fail the build if we have a defined but malformed analytics id
137+
const idPattern = /^(G|GTM)-[A-Z\d]+$/;
138+
for (const [name, value] of Object.entries({ VITE_GTM_ID, VITE_GTAG_ID })) {
139+
if (value && !idPattern.test(value)) {
140+
throw new Error(`Invalid ${name} value: '${value}'`);
141+
}
135142
}
136-
return [
137-
[
138-
'script',
139-
{ src: `https://www.googletagmanager.com/gtag/js?id=${env.VITE_GTAG_ID}`, async: '' },
140-
],
141-
[
142-
'script',
143-
{},
144-
`function gtag(){dataLayer.push(arguments)}window.dataLayer=window.dataLayer||[],gtag('js',new Date),gtag('config','${env.VITE_GTAG_ID}',{anonymize_ip:true})`,
145-
],
146-
];
143+
144+
const tags: HeadConfig[] = [];
145+
146+
if (VITE_GTAG_ID) {
147+
const source = `
148+
window.dataLayer = window.dataLayer || [];
149+
function gtag(){ dataLayer.push(arguments) }
150+
gtag('js', new Date);
151+
gtag('config', '${VITE_GTAG_ID}', { anonymize_ip: true });
152+
`;
153+
tags.push(['script', {}, source]);
154+
if (!VITE_GTM_ID) {
155+
const url = `https://www.googletagmanager.com/gtag/js?id=${VITE_GTAG_ID}`;
156+
tags.push(['script', { async: '', src: url }]);
157+
}
158+
}
159+
160+
// We're migrating from gtag.js to gtm.js, but using both as we verify this change.
161+
// According to https://support.google.com/tagmanager/answer/6103696 this should be
162+
// inserted after any script declaring a dataLayer.
163+
if (VITE_GTM_ID) {
164+
const source = `
165+
(function(w, d, s, l, i){
166+
w[l] = w[l] || [];
167+
w[l].push({'gtm.start': new Date().getTime(), event: 'gtm.js'});
168+
let f = d.getElementsByTagName(s)[0];
169+
let j = d.createElement(s);
170+
let dl = l != 'dataLayer' ? '&l=' + l : '';
171+
j.async = true;
172+
j.src = 'https://www.googletagmanager.com/gtm.js?id=' + i + dl;
173+
f.before(j);
174+
})(window, document, 'script', 'dataLayer', '${VITE_GTM_ID}');
175+
`;
176+
tags.push(['script', {}, source]);
177+
}
178+
179+
return tags;
147180
}
148181

149-
function getSearchConfig(env: NodeJS.ProcessEnv) {
182+
function getSearchConfig(env: NodeJS.ProcessEnv): ThemeConfig['search'] {
150183
if (env.VITE_ALGOLIA_ID && env.VITE_ALGOLIA_KEY) {
151184
return {
152185
provider: 'algolia',

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,14 +105,16 @@ For production, the docs expect the following environment variables to be define
105105

106106
- `VITE_ALGOLIA_ID`: Algolia `appId`.
107107
- `VITE_ALGOLIA_KEY`: Algolia `apiKey`.
108+
- `VITE_GTM_ID`: Google Tag Manager id.
108109
- `VITE_GTAG_ID`: Google Analytics id.
109110

110-
They can be defined in CI server configuration, or in a `.env` file:
111+
They can be defined in CI configuration, or in a `.env` file:
111112

112113
```sh
113114
# .env
114115
VITE_ALGOLIA_ID='******'
115116
VITE_ALGOLIA_KEY='******'
117+
VITE_GTM_ID='******'
116118
VITE_GTAG_ID='******'
117119
```
118120

0 commit comments

Comments
 (0)