Nuxt add GTM (noscript) to body tag on every page / route - vue.js

I am trying to implement Google Tag Manager on a Nuxt app and am stuck on how to add the noscript tag to the app on every page / route inside the opening body tag. I tried creating a static script and adding the file through the nuxt config:
{ src: "/scripts/gtm.js", body: true }
which added the file to the body but was throwing errors due to the noscript tag and nested iframe from gtm. Not sure if there is a better way to inject the actual script directly inside the body
<!-- Google Tag Manager (noscript) -->
<noscript><iframe
src="https://www.googletagmanager.com/ns.html?id=GT
M-4BXKY65"
height="0" width="0"
style="display:none;visibility:hidden"></iframe></n
oscript>
<!-- End Google Tag Manager (noscript) -->

#Eike is correct there. Noscript is completely useless in 99.99% of GTM usage cases. It's used when a user has JS off, but unlike what you think, it won't make GTM work with no JS. In fact, only one tag can "fire" in that state and that would be a rarely used custom image tag. Most commonly used for firing pixels.
Yes, noscript implies an iframe and if your app doesn't support them, well then no noscript for you. Really, Nuxt is a front-end rendering framework. Why would you have anything in your <noscript> other than asking the user to enable JS in order to see the site...

The head property in your nuxt.config.js lets you define all the meta data and scripts that appear on each page. It looks like you can add a noscript section for what you need.

This applies to Nuxt v2.
I added the noscript GTM code through layouts/default.vue. Doing that inserts it into body, albeit not completely at the end (which is probably fine). I had to use v-html to avoid hydration mismatch errors ("The client-side rendered virtual DOM tree is not matching server-rendered content.").
<template>
<noscript v-html="iFrameCode" />
</template>
<script>
export default {
data() {
return {
iFrameCode: '<iframe src="https://www.googletagmanager.com/ns.html?id=GTM-XYXYXYX" height="0" width="0" style="display: none; visibility: hidden" />',
}
},
}
</script>
What confused me a bit when testing the implementations was the following:
When I had JavaScript on, this is what I saw in Chrome Dev Tools:
But when I tried turning JavaScript off, the code seemed to run fine:

Related

Google maps API UI showing but contents are not loading; no error thrown, using VUE and API Key is used

I am currently using Vue and Vue2-google-maps. When my webpage is loaded, the UI for Google Map shows up (Zoom buttom, full screen) and when I try to drag the map around the console shows that I am recieving information from Google's API. However, the actual map itself is blank and nothing is showing.
<GmapMap :center="{lat:10, lng:10}" :zoom="12" map-type-id="terrain" style="width:750px; height:750px" ></GmapMap>
Under my main.js of Vue, I have declared my API key and use GoogleMaps accordingly.
Vue.use(VueGoogleMaps, {
load:{
key:'REDACTED',
}
});
I have ensured that my height and width are set to PX values, tried shaking the browser etc. I followed a separate tutorial that does not use Vue but those include a <script> tag inside the document html, which I am unable to do in Vue template as they are ignored. The console also does not show any errors at all.
I will appreciate any help! Thank you.
I found the solution. I had a CSS style for background color for all and that was overriding everything that Google Maps displayed. This style was in the app.vue parent component and I was troubleshooting in a child component hence I was unable to find the issue. Removing this <style> made everything work as normal again.
<style>
*{
background-color: aliceblue;
}
</style>

How to setup a netlify form in Nuxt

When I navigate to a form using vue-router by adding a link with a <router-link> element, the form does not work. When I hit submit I get a 404 response.
However, if I navigate to it using an <a> tag (triggering a page reload) then it works perfectly.
I suspect that this has to do with the page rendering as a SPA and for some reason not loading an important part of the form for Netlify unless the form page is reloaded? Why is this happening and is there an elegant solution to the problem? I could just replace all links to forms with tags but I'm sure that there is a better solution, I just don't understand the problem well enough to find it.
For context, I am using Nuxt. The forms are recognized by Netlify on the backend and can accept submission with the tag link so that is not the problem.
Since you're using Nuxt, you probably should go SSG/full static with target: 'static' (hostable on Netlify-like platforms) or with target: 'server' (hostable on Heroku-like platforms) but at any point, you should have ssr: true (default value). When you do have this, the biggest part is done.
In Nuxt, you should use <nuxt-link> rather than <router-link>, it works exactly the same (takes the same params etc) but it's more specific to Nuxt and SSR/SSG compatible while <router-link> is not. More details here: https://nuxtjs.org/docs/2.x/features/nuxt-components#the-nuxtlink-component
So, with all of this it should already work great. If it's not, I will gladly help you spot the issue if you have a github repo.
An alternative solution can be to use some form without any SSR dependency like Formspree: https://formspree.io/ (works fine with any SPA)
It works great, really simple. But I'd rather invite you to make a proper SSR form since you're using Nuxt.
PS: use <a> tags only for external links aka the ones which do not start with your domain name, nothing else. A follow of this kind of link is like a hard refresh and should be avoided at all costs.
EDIT: how to deploy by cleaning the cache.
EDIT on how to achieve a working form:
<template>
<div>
<form
netlify
action="/"
method="POST"
name="Contact"
>
<input type="hidden" name="form-name" value="Contact" />
<!-- ... -->
</form>
</div>
</template>
As told in the docs:
[...] inject a hidden input named form-name [...] and the hidden form-name input’s value matches the name attribute of form
Working fine. Could add a honeypot to it to make it even more secure!

Why is my frontend code behaving differently locally versus production?

Currently just a BootstrapVue VueJS frontend project I have, I have 4 playing cards that I would ideally like to keep on one line/row (as it does locally), but stacks when I view it in production (using Heroku, if it makes a difference)
Currently the code for this is like:
<div
flex-wrap="nowrap"
class="row d-flex nowrap mt-3"
justify-content="space-between"
width="100vw"
>
<b-container>
<b-row>
<b-col>
<PlayingCard/>
</b-col>
....etc for the other cards....
</b-row>
</b-container>
</div>
I've played around a lot with different classes and justify-contents and all that stuff, but continually get different local vs prod results. And I can confirm the code on Heroku is up to date because it redeploys with each new commit and I've added some new features since attempting to fix this styling issue and those appear properly.
Styling issues like that are most commonly due to scoping issues of your CSS. If you inspect the element locally you will likely see that only the local styling has been applied, while if you inspect the element in production, you will see that either the selector contains more CSS (due to identical selectors in two different components), or another selector is applied altogether.
You are getting this problem, because in dev-mode it only loads the CSS of the components you are viewing. In production mode, all the CSS of all components is combined.
To solve the problem, you have several options:
You can use the scoped attribute on your style tag. Vue will automatically add a data-attribute on your component, and scope the styling using that data attribute. This does commonly not work nicely with things like popups that are moved out of their previous location.
<template>
<div>
<!-- something here -->
</div>
</template>
<script>
export default {
//...
}
</script>
<style scoped>
button {
// This only styles the buttons in this component, rather than every button in the application
}
</style>
If you need to style sub-components as well, you can just use a class on your root element and style everything relative to that. You would need to make that class a unique name in your application, but if you just use the name of your component that shouldn't be a problem.
<template>
<div class="comp-card">
<!-- something here -->
</div>
</template>
<script>
export default {
name: 'Card'
}
</script>
<style lang="scss">
.comp-card {
button {
// All buttons that are descendants of our component are now styled.
}
}
</style>
I see two issues with the given code, addressing these may not resolve your issue, but may remove some interference.
Bootstrap provides the class .flex-nowrap for applying flex: nowrap – it should be noted that nowrap is the default behaviour of flexbox, and this may not be needed anyway.
Some attributes in your div appear to be style declarations, and ought to be in the [style] attribute as shown below, or a <style> tag if using SFCs
<div
class="row d-flex mt-3"
style="justify-content: space-between; width: 100vw"
>
Caching of applicable files can vary between local and production environments.
Browsers accessing production servers may cache older versions of files and make it appear that the change was not made. The server may have newer files than what the browser is using.
UI changes in production might be issue of CSS Optimization in build process of vue cli.
Did you try to serve/run build locally if it works then it might issue on production site/cache/browser etc. Try local build with serve or any other tool to verify.
If css optimization issue in build then re-configure build config with underlying tool like webpack or vite etc whichever used.

Vue app with Netlify form throws error binding to events

I am trying to hide/show a div if a form-input has a value. This works just fine with a regular form but if I implement it with netlify-forms I get the following error:
Unhandled promise rejection TypeError: "setting getter-only property "message""
<form name="newsletter" method="POST" data-netlify="true">
<input #input="email = $event.target.value" type="email" name="email">
<div :class="{'hidden': email === ''}">
<div data-netlify-recaptcha="true" />
</div>
</form>
I also tried #focus and #blur instead of #input but the error is always the same.
Without the data-netlify="true" it works as expected so I suspect it to have something to do with Netlify injecting something into the form.
In Netlify's guide on Netlify Forms + Vue, they say that the way SPAs are rendered can prevent Netlify's bots from HTML-editing the form to link it with their services.
By default Vue renders client side but the Netlify post processing bots expect HTML on site deploy. Any netlify form attribute tags included in a Vue app would only be inserted into the DOM client-side, rather than in the HTML and thereby runs the risk of being totally overlooked by the build bots.
To handle this, you have two options. You can either pre-render your application or add the netlify form to your static HTML file in your public folder.
So either pre-render your HTML (which gives an added speed and SEO bonus), or give netlify a static form to attach itself to, which you can then hide and replace with your nice Vue form on the client.

Basic custom element does not seem to work

I'm trying to create a standard user status widget for my Aurelia app, and I'm not sure what I'm doing wrong. As a starting point I followed the docs, but my results aren't what they tell me to expect and I'm not getting errors either in build nor in the browser.
Relevant files are as follows:
<!-- nav-bar.html -->
<template bindable='router'>
<require from="./user-status "></require>
<!-- various nav buttons -->
<p class="navbar-collapse collapse navbar-text">
Test <user-status></user-status>
</p>
user-status.html
<template>
${status}
</template>
user-status.js
export default class UserStatusCustomElement {
constructor() {
this.status = 'Be sure to drink your Ovaltine!';
}
}
if I change the require in nav-bar.html to look for ./user-status.html it appears to have an effect (additional aurelia-looking attributes are added to the user-status element in the rendered html) but does not render the message (one assumes b/c it's not picking up the class and rendering as an html-only thing). If I leave as-is, it doesn't error but those attributes are not added and nothing is rendered, even static text.
I played around with your code and found that removing default from the user-status.js module fixed the problem. I suspect the reason has something to do with how Aurelia utilizes module-loaders (System.js, webpack, ...) when importing modules. Unfortunately I don't know enough about the internals of Aurelia to give a more in-depth answer.