Snipcart and NextJS installation - javascript

I feel like this is driving me crazy, not being able to get Snipcart set up properly and I am not sure how to resolve this. Maybe someone can tell me what I'm missing here?
So I can add the link references in the 'Head' of the '_document' page just fine, but on Snipcart's installation docs, it says to put this script right after the element, except it throws errors anywhere I put it. Here is the installation script you need to add:
<script>
window.SnipcartSettings = {
publicApiKey: "YOUR_API_KEY",
loadStrategy: "on-user-interaction",
};
(()=>{var c,d;(d=(c=window.SnipcartSettings).version)!=null||(c.version="3.0");var s,S;(S=(s=window.SnipcartSettings).timeoutDuration)!=null||(s.timeoutDuration=2750);var l,p;(p=(l=window.SnipcartSettings).domain)!=null||(l.domain="cdn.snipcart.com");var w,u;(u=(w=window.SnipcartSettings).protocol)!=null||(w.protocol="https");var f=window.SnipcartSettings.version.includes("v3.0.0-ci")||window.SnipcartSettings.version!="3.0"&&window.SnipcartSettings.version.localeCompare("3.4.0",void 0,{numeric:!0,sensitivity:"base"})===-1,m=["focus","mouseover","touchmove","scroll","keydown"];window.LoadSnipcart=o;document.readyState==="loading"?document.addEventListener("DOMContentLoaded",r):r();function r(){window.SnipcartSettings.loadStrategy?window.SnipcartSettings.loadStrategy==="on-user-interaction"&&(m.forEach(t=>document.addEventListener(t,o)),setTimeout(o,window.SnipcartSettings.timeoutDuration)):o()}var a=!1;function o(){if(a)return;a=!0;let t=document.getElementsByTagName("head")[0],e=document.querySelector("#snipcart"),i=document.querySelector(`src[src^="${window.SnipcartSettings.protocol}://${window.SnipcartSettings.domain}"][src$="snipcart.js"]`),n=document.querySelector(`link[href^="${window.SnipcartSettings.protocol}://${window.SnipcartSettings.domain}"][href$="snipcart.css"]`);e||(e=document.createElement("div"),e.id="snipcart",e.setAttribute("hidden","true"),document.body.appendChild(e)),v(e),i||(i=document.createElement("script"),i.src=`${window.SnipcartSettings.protocol}://${window.SnipcartSettings.domain}/themes/v${window.SnipcartSettings.version}/default/snipcart.js`,i.async=!0,t.appendChild(i)),n||(n=document.createElement("link"),n.rel="stylesheet",n.type="text/css",n.href=`${window.SnipcartSettings.protocol}://${window.SnipcartSettings.domain}/themes/v${window.SnipcartSettings.version}/default/snipcart.css`,t.prepend(n)),m.forEach(g=>document.removeEventListener(g,o))}function v(t){!f||(t.dataset.apiKey=window.SnipcartSettings.publicApiKey,window.SnipcartSettings.addProductBehavior&&(t.dataset.configAddProductBehavior=window.SnipcartSettings.addProductBehavior),window.SnipcartSettings.modalStyle&&(t.dataset.configModalStyle=window.SnipcartSettings.modalStyle),window.SnipcartSettings.currency&&(t.dataset.currency=window.SnipcartSettings.currency),window.SnipcartSettings.templatesUrl&&(t.dataset.templatesUrl=window.SnipcartSettings.templatesUrl))}})();
</script>
Putting this script anywhere in '_document' throws an error, after doing a bunch of trial and error. I cannot figure out how to get Snipcart working properly with NextJS and documentation on installation alone seems to be hard to find - which means people don't usually have an issue with it, right? Haha. I am losing my mind on this, and it's probably an easy fix I have overlooked somewhere. Any help is appreciated!
This is where the script is located, in '_document':
import { Html, Head, Main, NextScript } from "next/document";
export default function Document() {
return (
<Html>
<Head>
...
</Head>
<body>
<Main />
<NextScript />
<script>
window.SnipcartSettings = {
publicApiKey: "YOUR_API_KEY",
loadStrategy: "on-user-interaction",
};
(()=>{var c,d;(d=(c=window.SnipcartSettings)...
</script>
</body>
</Html>
);
}

Found the solution here:
NextJS Snipcart Installation - github
Omit the 3 links. Not needed.

Related

Gatsby site, Script not available on first page request with Helmet

I have a Gatsby site that I'm trying to add a third-party js widget to but for some strange reason it will only load if I refresh the page manually. On first page load, it as is if it doesn't exist at all, no errors in dev-tools, nothing... but if I refresh the page, it then appears. It's almost as if it's lazy loading? Is there a way to force load?
I've checked the elements, console, and network tabs in dev tools but there's nothing to indicate any errors. elements shows the tags that I would expect, console shows nothing at all, and network everything shows up with 200.
Could this be an issue with Gatsby and/or Helmet, it might be but I don't think it's an issue with the widget itself (it's third-party, I have no control over it, see last paragraph)?
<Helmet
script={[
{
type: 'text/javascript',
src: '//widget-url.com/path/to/jsfile.min.js',
},
{
type: 'text/javascript',
innerHTML: `
(function() {
var widget = Stuff.happens.here();
widget.Initialise();
})();
`,
},
]}
/>
In the body I then have:
<div id='widget-id'></div>
Things I've tried to attempt to understand where the issue is:
As I mentioned, I have to force refresh the page where the widget is located. If I force refresh any other page, it doesn't help. So something I tried is: rather than only including the JS into the head of the page in question, I would including it on ALL pages. But this has made no difference.
I've also tried adding the widget to a simple stand-alone html file, the widget loads without problem. Which leads me to think that it's probably not a widget issue?
I don't know where to go from here :(
The problem is that you are pointing a DOM element that may or may not be rendered at the moment your request the script.
In your case, I'd try:
<Helmet>
<script async defer src="//widget-url.com/path/to/jsfile.min.js" />
<script async defer>
{`
(function() {
var widget = Stuff.happens.here();
widget.Initialise();
})();
`}
</script>
</Helmet>
Or using one of the multiple Server-Side Rendering APIs. onRenderBody should work:
// gatsby-ssr.js
import React from "react"
export const onRenderBody = ({ setHeadComponents, setPostBodyComponents }) => {
setHeadComponents([
<script
src="//widget-url.com/path/to/jsfile.min.js"
type="text/javascript"
async
/>,
<script
dangerouslySetInnerHTML={{
__html: `
(function() {
var widget = Stuff.happens.here();
widget.Initialise();
})();
`,
}}
/>,
])
}

How to use mailerlite popups in a Next.js application

I'm integrating a mailerlite popup for a client's next.js project, and I'm having a difficult time converting the JavaScript snippets into the jsx required to make the popups function properly. On first load it seems to work just fine, but on relaod I'm getting the following error.
window is not defined
I've encountered the issue while dealing with DOM manipulation, but in this case, judging from the code in the snippet, I need the window object.
Install the following snippet of Javascript on every page of your website right before the closing tag.You only need to add this snippet once, even if you plan to have a few different webforms.
<!-- MailerLite Universal -->
<script>
(function(m,a,i,l,e,r){ m['MailerLiteObject']=e;function f(){
var c={ a:arguments,q:[]};var r=this.push(c);return "number"!=typeof r?r:f.bind(c.q);}
f.q=f.q||[];m[e]=m[e]||f.bind(f.q);m[e].q=m[e].q||f.q;r=a.createElement(i);
var _=a.getElementsByTagName(i)[0];r.async=1;r.src=l+'?v'+(~~(new Date().getTime()/1000000));
_.parentNode.insertBefore(r,_);})(window, document, 'script', 'https://static.mailerlite.com/js/universal.js', 'ml');
var ml_account = ml('accounts', '912433', 'd5p1f7l9g0', 'load');
</script>
<!-- End MailerLite Universal -->
I've placed this code in my Layout wrapper. As previously stated, it works fine on first load, but as soon as the user navigates to a new page above error shows up.
PS I found an old question regarding this topic here, but it's old and not quite relevant to my situation. I need to figure out how to convert the above snippet for nextjs. Any help at all would be appreciated.
This approach treats the MailerLite universal tag as its own <script> hosted on your site's domain.
Add a NextJS custom document.
Create a JavaScript file containing the MailerLite universal tag code in ./public. I put mine in ./public/scripts/ml.js.
Add a <script> tag loading #2 in your custom _document.js file:
import Document, { Html, Head, Main, NextScript } from 'next/document'
class MyDocument extends Document {
static async getInitialProps(ctx) {
const initialProps = await Document.getInitialProps(ctx)
return { ...initialProps }
}
render() {
return (
<Html>
<Head>
<script async src="/scripts/ml.js"></script>
</Head>
<body>
<Main />
<NextScript />
</body>
</Html>
)
}
}
export default MyDocument
Everything worked as intended from there! (Caveat: I'm only using embedded forms).

Gatsby-js client side javascript inline in blog post

I am trying to setup a Blog using Gatsby-JS. I have some posts in markdown that contain inline javascript.
As an example:
<script>window.alert("hello");</script>
I test the site using the command "Gatsby serve"
When I browse to my post via the index of the blog. The script is not executed. In the web console there are no errors.
When on the post page itself. If I do F5 or ctrl-f5 then the "hello" alert is displayed.
After uploading the site to github pages this behavior changes. I cannot get the script to execute by F5 or by navigating via the index. Only when I press ctrl+F5 the script is executed.
live test-blog can be found here (it show multiple alerts and tries to load plotly). https://dwjbosman.github.io/lstm-neural-network-for-sequence-learning/
Dinne's solution worked for me. Nice one! :)
I did need to avoid the use of JQuery though so I have posted here a version that doesn't rely on it:
componentDidMount() {
// Allow in-line JS scripts to be run
let scripts = document.querySelectorAll('[data-inline-script="data-inline-script"]');
scripts.forEach(function forEachScript(element) {
const script = element.innerHTML;
window.eval(script);
});
This will work with the following HTML:
<script data-inline-script="data-inline-script">
console.log("this works");
</script>
I am using this on a very basic static site. I'm not sure how much I like using eval() to be honest but it should cause no harm in my use-case.
Update
Although the above does work, I also need to include scripts using <script src="..."> which doesn't work :( This feels quite hacky too.
Checkout this question React: Script tag not working when inserted using dangerouslySetInnerHTML
Script in HTML that is inserted by React's dangerouslySetInnerHTML won't get executed. The linked question has a work around that perhaps you can use.
The previous answer pointed me in the right direction.
I gave all the inline scripts an attribute data-my-script. Next I added the following to layouts/index.jsx (not html.jsx as this is rendered only server side).
componentDidMount() {
let scripts = window.jQuery.find('[data-my-script]')
console.log(scripts);
scripts.forEach(function forEachScript(element) {
const script = window.jQuery(element).text();
window.eval(script);
});
}
render() {
const { children } = this.props;
return (
<Navigation config={config} LocalTitle={this.getLocalTitle()}>
<div ref={contentElement => (this.contentElement = contentElement)}>
<Helmet>
<meta name="description" content={config.siteDescription} />
// for plotly inside notebooks
// <script src="https://cdn.plot.ly/plotly-latest.min.js" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.5/require.min.js"/>
<script src="https://code.jquery.com/jquery-3.2.1.min.js"/>
</Helmet>
{children()}
</div>
</Navigation>
);
}
}

Variable is not defined error in my Firefox extension

I'm developing a Firefox add-on. When I run it, I open up the browser console and it says, AMO_Uedit_Beta_Firefox is not defined :browser.xul.
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://Uedit/skin/skin.css" type="text/css"?>
<!DOCTYPE Uedit SYSTEM "chrome://Uedit/locale/translations.dtd">
<overlay id="Uedit-overlay" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script src="Uedit.js" />
<toolbarpalette id="BrowserToolbarPalette">
<toolbarbutton id="Uedit" class="toolbarbutton-1" label="Edit HTML" tooltiptext="Edit HTML" oncommand="AMO_Uedit_Beta_Firefox.Uedit()" />
</toolbarpalette>
</overlay>
The toolbar button that calls a function which is part of an object (AMO_Uedit_Beta_Firefox).
I double-checked the names and they both match. Is it because the script doesn't load properly? I'm sure it's not that variable names can't start with capital letters.
var AMO_Uedit_Beta_Firefox={ // This is for "wrapping the loose variables."
Both the file's references are the exact same. Could it be because the script didn't load at all?
<toolbarbutton id="Uedit" class="toolbarbutton-1" label="Edit HTML" tooltiptext="Edit HTML" oncommand="AMO_Uedit_Beta_Firefox.Uedit()" />
I tried changing the relative URL (<script src="Uedit.js" />) to an absolute URL (<script src="chrome://Uedit/Uedit.js" />) in the browser.xul, but now it just returns a blank error message.
Weird blank error message.
These errors cause the rest of the add-on to not work at all, so I can't continue developing it until this is fixed. What're some possible solutions?
EDIT:
I figured out a solution. I have to put a line of JavaScript before the first statement.
var AMO_Uedit_Beta_Firefox = { // Will not work!
...
If I put a console.log in the front, for example.
console.log("");
var AMO_Uedit_Beta_Firefox = { // This will work!
...
The only question is, why does this work?
It looks like the path to the Uedit.js file is wrong. You should use an absolute path in your xul overlay.
As erikvold has said, the link to your Uedit.js script is wrong. This is the minimum that is wrong and is the thing that is complained about in the console: browser.xul:5 is line 5 in browser.xul, which is:
<script src="Uedit.js" />
You state that you have tried:
<script src="chrome://Uedit/Uedit.js" />
That will not work. At a minimum, it should be something like:
<script src="chrome://Uedit/content/Uedit.js" type="application/x-javascript" />
Note the content/ after //Uedit/. However, that being correct assumes you have set up your chrome.manifest with an appropriate content line in addition to the other ones implied by your code (skin and locale). It also assumes that Uedit.js is in that directory. Assuming that the directory structure of your add-on is normal, the content line in your chrome.manifest file would look something like:
content Uedit chrome/content/
As to it actually working, there is no way for us to know if it will work as you have not included the source code that defines all of AMO_Uedit_Beta_Firefox and specifically not AMO_Uedit_Beta_Firefox.Uedit(). For instance, in addition to the above problem, there could easily be a syntax error that prevents the script from loading. Such a syntax error would cause the console to report that AMO_Uedit_Beta_Firefox was undefined when you attempt to execute AMO_Uedit_Beta_Firefox.Uedit() as the code for the toolbarbutton's oncommand.
You can easily test to see if your Uedit.js script is loading by having something print in the console when the script loads (i.e. outside the definition of AMO_Uedit_Beta_Firefox).
I figured out a solution. I have to put a line of JavaScript before the first statement.
var AMO_Uedit_Beta_Firefox = { // Will not work!
...
If I put a console.log in the front, for example.
console.log("foo bar");
var AMO_Uedit_Beta_Firefox = { // This will work!
...
I solved the problem myself, although the solution is strange.

Getting "cannot call method ... of undefined" error with JavaScript and Mustache

I'm using HTML, JavaScript, and jQuery Mobile to make a kind of picture gallery. I'm following the JQM demo at: http://jquerymobile.com/demos/1.3.0-beta.1/docs/demos/swipe/swipe-page.html
to make the gallery, but it uses a totally different HTML page for each picture. My plan is for the gallery to be dynamic, so I don't have a set number of pages or a set list of picture names, etc, and I thought I might use Mustache to make a picture template, and create the pages dynamically. Here is the basic layout of the code:
In index.html
<!DOCTYPE html>
<html>
<head>
...
<script src="mustache-0.7.0-min.js" type="text/javascript"></script>
<script src="mobile.js" type="text/javascript"></script>
<script id="test_template" type="text/html">
<h1>{{firstName}} {{lastName}}</h1>
<p>{{tempText}}</p>
</script>
...
</head>
...
And then in mobile.js
function showPerson()
{
var person =
{
firstName: "Feaf",
lastName: "McFeaf",
tempText: "Hello Feaf"
};
var personTemplate = document.getElementById("test_template").innerHTML;
var html = Mustache.to_html(x, person);
}
So it's about as basic as you can get. However, when I run the web app on a local server (in Chrome), and I step through this function, I get an error at the Mustache.to_html line, saying
Uncaught TypeError: Cannot call method 'to_html' of undefined
I'm fairly new to web development, and brand new to Mustache, so I do not know what could be causing this error. I've tried calling other Mustache methods, like render, but the same error appears. Is the <script src=...> not enough to have the Mustache library accessible to mobile.js? Anybody have any tips on what I might be doing wrong?
Thank you for any information, and let me know of any other information I should add.
EDIT:
Whoops! Forgot to include the fact that I had mustache in the scripts section, I've edited to reflect this fact. Just to be clear, I DO have (and always have had) mustache included!
Also, I tried the suggestion of #Zorayr of using console.log(Mustache), and it claims that Mustache is undefined, even though I am importing it as noted above. Why might this be?
As a solution to the problem, I ended up downloading and using Handlebars. It seems to me that there was some conflict with the Mustache library that was already in the project and the new one I added in. This doesn't really explain why Mustache would be undefined, but that was my workaround.

Categories

Resources