I've been working with @torgosPizza on this. Based on research and testing, I can confirm that gtag does include and invoke analytics.js. This can be demonstrated using this basic test page
<html>
<head>
<!-- Google tag (gtag.js) -->
<script async src="https://www.googletagmanager.com/gtag/js?id=REDACTED"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'REDACTED');
</script>
</head>
<body>
gtag.js test
</body>
</html>
and noting that window.ga is defined.
Gtag provides analytics.js for backward compatibility, and I believe it currently uses it internally. This is why overriding window.ga() with new function that calls gtag() can cause the recursive behavior being seen. I suspect Google may change that in July when Universal Analytics is deprecated at which point the shim may be needed to retain compatibility with callers of ga().
Note: UBlock Origin substitutes its own code for gtag accounting for the difference in behavior when that ad blocker is enabled.
@mglaman: a note on your shim as described above. To provide a shim for ga() in case it is not defined, I'd use a construction like this:
window.ga = window.ga || function() {
...
}
Block level function declarations are weird and inconsistent: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statem...