@@ -6,21 +6,21 @@ import { defaultGroupLink, sidebarLinks } from '../docs/links';
66
77dotenv . 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
1212interface 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
1919export 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 | G T M ) - [ 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' ,
0 commit comments