Skip to main content

5 posts tagged with "javascript"

View All Tags

· 5 min read
Ziinc

EmailOctopus is a lovely newsletter site, and I do enjoy the fact that their UI is quite well done and user friendly, and on the technical side they have EmailOctopus Connect, which is allows for lower email costs. They bill by subscriber count though, so for any seriously large subscriber counts it would make more sense to self-host, but I like using them for small projects (like this blog for example) which will never ever see more than a handful of subscribers.

However, EmailOctopus could definitely up their game when it comes to their developer APIs and scripts. Their embeddable script is an absolute pain to work with when it comes to custom websites, especially if you're using a shadow DOM.

<script
async
src="https://eomail1.com/form/983899ac-29fb-11ef-9fcd-4756bf35ba80.js"
data-form="983899ac-29fb-11ef-9fcd-4756bf35ba80"
defer
type="text/javascript"
></script>

Let me break this down for you:

  • It loads a script asyncronously. The script is custom generated for the specific form created, as can be seen by the usage of the uuid in the script URL.
  • The script will insert a form as well as load some additional some Google reCaptcha scripts for spam protection. It will also load some Google Fonts and any assets related to the form.
  • By default, it does not come wiht the defer and type attributes. These were added in by me, and would ensure that the browser executes it as JavaScript, and that execution would be deferred until the DOM is fully loaded.
  • It finds a <script> tag with the data-form attribute with that exact UUID and replaces it with the form. It then creates the required DOM nodes within the HTML page.

However, adding in the script directly to a React component would not work:

// 🚫 This will not work!
const MyComponent = () => (
<div>
<script
async
src="https://eomail1.com/form/983899ac-29fb-11ef-9fcd-4756bf35ba80.js"
data-form="983899ac-29fb-11ef-9fcd-4756bf35ba80"
defer
type="text/javascript"
></script>
</div>
);

Why wouldn't this work?

  • React works with a shadowDOM, and thus there would not be any script tag available on the html at page load. React will mount the component on client load.
  • Even with React Server Side Rendering, the script tag would not be executed because React protects from malicious code that will set raw html inside components. One would need to use __dangerouslySetInnerHtml in order for this to work

This, we need to adjust our React code in Docusaurus to:

  1. execute the script; and then
  2. create the HTML tags at the <script> tag; but
  3. only do it client side;
Why do we want it to be only client side?

Docusaurus will generate both server and client code during the build step. Although it would would actually have some benefits have generated so that there is less JS running on client initial load, there is added complexity in trying to wrangle with the Docusaurus SSR build step, so just leaving it client side is fine as well. It also are no SEO benefits to be gained, so leaving it client side is fine.

For any other React library, this would likely be irrelevant.

Step 1: Create the Form​

Create the form inside EmailOctopus and obtain the embed script.

Example of form creation

Step 2: Add the wrapped component to your layout​

Add in the <Newsletter /> tag to whereever you want to slot your newsletter form at. You can also swizzle one of the layout components, but how to do that is out of scope for this blog post.

import React from "react";
import Newsletter from "@site/src/components/Newsletter";
export default function MyComponent(props) {
return (
<>
<Newsletter />
...
</>
);
}

Step 3: Install React Helmet​

We'll need some way to load the script in the head of the HTML document. We'll reach for React Helmet in this walkthrough guide, so do the current variation du jour of npm install --save react-helmet.

Step 3: Add in the Newsletter component​

For our component to work successfully, we need to create a the file at /src/components/Newsletter.tsx and define the compoennt as such:

//  /src/components/Newsletter.tsx
import React from "react";
import { Helmet } from "react-helmet-async";
import BrowserOnly from "@docusaurus/BrowserOnly";
const Newsletter = () => (
<div
style={{
marginLeft: "auto",
marginRight: "auto",
}}
>
<BrowserOnly>
{() => (
<>
<Helmet>
<script
async
defer
src="https://eomail1.com/form/983899ac-29fb-11ef-9fcd-4756bf35ba80.js"
type="text/javascript"
></script>
</Helmet>
<script
type="text/javascript"
data-form="983899ac-29fb-11ef-9fcd-4756bf35ba80"
></script>
</>
)}
</BrowserOnly>
</div>
);
export default Newsletter;

In this page, there are a few things that are going on:

  1. We set the script to the <Helmet /> component, meaning that this would be placed in the <head> tag of the HTML document. Two additiona attributes are added as well: defer to load this after the main document loads, and type="text/javascript" for completeness.
  2. We also add in the extra <script> tag in the component, with the data-form attribute to let the script identify it as the parent node to insert the form elements.
  3. We also wrap all of this inside of the <BrowserOnly /> component that comes with Docusaurus, which allows us to only run this code when on the client. As these scripts do not affect SEO, it is not necessary to include it in the server side generation.

Step 4: Verify it all works​

Now check that it all works on your localhost as well as on production, and now pat yourself on the back!

· 4 min read
Ziinc

Generating pages dynamically instead of relying on a 1-1 relationship of files to web pages seems to be an often overlooked aspect of static site generators, and Docusaurus is no exception. However, with some prowess and tinkering with the plugin system, we can definitely make the "impossible" possible, and generate pages from whatever data source we want.

Interested? Read on...

· One min read
Ziinc

Supabase Auth features are like a God's gift from heaven for having a record-speed authentication system ready to go for your side projects whenever you need.

However, since @supabase/supabase-js up to v2 (at time of writing) is meant for JAMstack developers, it does take some additional configuration to use it for the Node.js environment.

You will need to some additional configuration:

// ANON_KEY and ANON_URL are string constants from your project
createClient(ANON_URL, ANON_KEY, {
auth: { persistSession: false, autoRefreshToken: false },
})

This will disable attempts by the client to store and refresh session, as there is no localStorage in server/scripting environments.

Your API calls will now work flawlessly 🔥.

Shoutout to Kang Ming and Alaister for this, my awesome colleagues at Supabase, whose deep knowledge of the client during a discussion in Bali Nov 2022 led to the above snippet.

· 4 min read
Ziinc

I really enjoy developing with Ant Design. Yes, I know that it is a rather enterprise-y component library to work with when developing UIs in React, but I think that it has one of the fastest time-to-value as compared to any other component library, due to the sheer.

In this blog post, I will give you a quick walkthrough of how to combine the two tools together, and also give some opinionated tips on working with them.

· 8 min read
Ziinc

Dum dum dum...another one bites the dust! Another massively used JavaScript project can now rest in peace, alongside the thousands of other popular yet dead and unmaintained open-source JavaScript projects.

However, why this death is sort-of important is because of NetlifyCMS' namesake and the main backer of this open-source project: Netlify.