Constructing A Static-First MadLib Generator With Moveable Textual content And Netlify On-Demand Builder Capabilities

No Comments

Creating an interactive expertise with fiction could be a chore with conventional content material administration instruments. Writing the prose, creating the varieties, combining them within the frontend — these are sometimes the area of three completely different individuals.

Let’s make it the area of only one content material creator through which the person will fill out a type earlier than studying the story — creating odd and sometimes humorous tales. Any such expertise was popularized as “Madlibs.”

Generate your individual madlibs within the demo;
Look by way of the ultimate code on Github;
Get a fully-built model arrange in your accounts.

How The Generator Will Work

An editor can create a collection of madlibs that an end-user can fill out and save a duplicate with their distinctive solutions. The editor shall be working with the Sanity Studio inside a rich-text discipline that we’ll craft to offer further info for our front-end to construct out varieties.

For the editor, it can really feel like writing customary paragraph content material. They’ll be capable of write like they’re used to writing. They’ll then create particular blocks inside their content material that may specify part of speech and show textual content.

The front-end of the appliance can then use that information to each show the textual content and construct a type. We’ll use 11ty to create the frontend with some small templates. The shape that’s constructed will show to the person earlier than they see the textual content. They’ll know what kind of speech and basic context for the phrases and phrases they’ll enter.

After the shape is submitted, they’ll be given their absolutely shaped story (with hopefully hilarious outcomes). This creation will solely be set inside their browser. In the event that they want to share it, they’ll then click on the “Save” button. It will submit your complete textual content to a serverless operate in Netlify to reserve it to the Sanity information retailer. As soon as that has been created, a hyperlink will seem for the person to view the everlasting model of their madlib and share it with mates.

Since 11ty is a static website generator, we are able to’t depend on a website rebuild to generate every person’s saved Madlib on the fly. We are able to use 11ty’s new Serverless mode to construct them on request utilizing Netlify’s On-Demand Builders to cache every Madlib.

The Instruments

Sanity.io

Sanity.io is a unified content material platform that believes that content material is information and information can be utilized as content material. Sanity pairs a real-time information retailer with three open-source instruments: a strong question language (GROQ), a CMS (Sanity Studio), and a rich-text information specification (Moveable Textual content).

Moveable Textual content

Moveable Textual content is an open-source specification designed to deal with wealthy textual content as information. We’ll be utilizing Moveable Textual content for the wealthy textual content that our editors will enter right into a Sanity Studio. Information will enhance the wealthy textual content in a method that we are able to create a type on the fly primarily based on the content material.

11ty And 11ty Serverless

11ty is a static website generator inbuilt Node. It permits builders to ingest information from a number of sources, write templates in a number of templating engines, and output easy, clear HTML.

Within the upcoming 1.0 launch, 11ty is introducing the idea of 11ty Serverless. This replace permits websites to make use of the identical templates and information to render pages by way of a serverless operate or on-demand builder. 11ty Serverless begins to blur the road between “static website generator” and server-rendered web page.

Netlify On-Demand Builders

Netlify has had serverless features as a part of its platform for years. For instance, an “On-Demand Builder” is a serverless operate devoted to serving a cached file. Every builder works equally to an ordinary serverless operate on the primary name. Netlify then caches that web page on its edge CDN for every further name.

Constructing The Enhancing Interface And Datastore

Earlier than we are able to dive into serverless features and the frontend, it might be useful to have our information arrange and able to question.

To do that, we’ll arrange a brand new undertaking and set up Sanity’s Studio (an open-source content material platform for managing information in your Sanity Content material Lake).

To create a brand new undertaking, we are able to use Sanity’s CLI instruments.

First, we have to create a brand new undertaking listing to accommodate each the front-end and the studio. I’ve known as mine madlibs.

From inside this listing within the command line, run the next instructions:

npm i -g @sanity/cli
sanity init

The sanity init command will run you thru a collection of questions. Identify your undertaking madlibs, create a brand new dataset known as manufacturing, set the “output path” to studio, and for “undertaking template,” choose “Clear undertaking with no predefined schemas.”

The CLI creates a brand new Sanity undertaking and installs all of the wanted dependencies for a brand new studio. Contained in the newly created studio listing, we’ve every part we have to make our modifying expertise.

Earlier than we create the primary interface, run sanity begin within the studio listing to run the studio.

Creating The madlib Schema

A set of schema defines the studio’s modifying interface. To create a brand new interface, we’ll create a brand new schema within the schema folder.

// madlibs/studio/schemas/madlib.js

export default {
// Identify within the information
title: ‘madlib’,
// Title seen to editors
title: ‘Madlib Template’,
// Sort of schema (at this stage both doc or object)
kind: ‘doc’,
// An array of fields
fields: [
{
name: ‘title’,
title: ‘Title’,
type: ‘string’
},
{
title: ‘Slug’,
name: ‘slug’,
type: ‘slug’,
options: {
source: ‘title’,
maxLength: 200, // // will be ignored if slugify is set
}
},
]
}

The schema file is a JavaScript file that exports an object. This object defines the info’s title, title, kind, and any fields the doc may have.

On this case, we’ll begin with a title string and a slug that may be generated from the title discipline. As soon as the file and preliminary code are created, we have to add this schema to our schema.js file.

// /madlibs/studio/schema/schema.js

// First, we should import the schema creator
import createSchema from ‘half:@sanity/base/schema-creator’

// Then import schema varieties from any plugins that may expose them
import schemaTypes from ‘all:half:@sanity/base/schema-type’

// Imports our new schema
import madlib from ‘./madlib’

// Then we give our schema to the builder and supply the end result to Sanity
export default createSchema({
// We title our schema
title: ‘default’,
// Then proceed to concatenate our doc kind
// to those supplied by any plugins which might be put in
varieties: schemaTypes.concat([
// document
// adds the schema to the list the studio will display
madlib,
])
})

Subsequent, we have to create a wealthy textual content editor for our madlib authors to jot down the templates. Sanity has a built-in method of dealing with wealthy textual content that may convert to the versatile Moveable Textual content information construction.

To create the editor, we use an array discipline that comprises a particular schema kind: block.

The block kind will return all of the default choices for wealthy textual content. We are able to additionally lengthen this sort to create specialty blocks for our editors.

export default {
// Identify within the information
title: ‘madlib’,
// Title seen to editors
title: ‘Madlib Template’,
// Sort of schema (at this stage both doc or object)
kind: ‘doc’,
// An array of fields
fields: [
{
name: ‘title’,
title: ‘Title’,
type: ‘string’
},
{
title: ‘Slug’,
name: ‘slug’,
type: ‘slug’,
options: {
source: ‘title’,
maxLength: 200, // // will be ignored if slugify is set
}
},
{
title: ‘Madlib Text’,
name: ‘text’,
type: ‘array’,
of: [
{
type: ‘block’,
name: ‘block’,
of: [
// A new type of field that we’ll create next
{ type: ‘madlibField’ }
]
},
]
},
]
}

This code will arrange the Moveable Textual content editor. It builds varied forms of “blocks.” Blocks roughly equate to top-level information within the JSON information that Moveable Textual content will return. By default, customary blocks take the form of issues like paragraphs, headers, lists, and many others.

Customized blocks might be created for issues like photos, movies, and different information. For our madlib fields, we wish to make “inline” blocks — blocks that stream inside one in every of these bigger blocks. To try this, the block kind can settle for its personal of array. These fields might be any kind, however we’ll make a customized kind and add it to our schema in our case.

Creating A Customized Schema Sort For The Madlib Area

To create a brand new customized kind, we have to create a brand new file and import the schema into schema.js as we did for a brand new doc kind.

As a substitute of making a schema with a sort of doc, we have to create one in every of kind: object.

This practice kind must have two fields: the show textual content and the grammar kind. By structuring the info this fashion, we open up future potentialities for inspecting our content material.

Alongside the info fields for this sort, we are able to additionally specify a customized preview to point out a couple of discipline displayed within the wealthy textual content. To make this work, we outline a React part that may settle for the info from the fields and show the textual content the way in which we wish it.

// /madlibs/studio/schemas/object/madLibField.js
import React from ‘react’

// A React Element that takes hte worth of information
// and returns a easy preview of the info that can be utilized
// within the wealthy textual content editor
operate madlibPreview({ worth }) {
const { textual content, grammar } = worth

return (

{textual content} ({grammar})

);
}

export default {
title: ‘Madlib Area Particulars’,
title: ‘madlibField’,
kind: ‘object’,
fields: [
{
name: ‘displayText’,
title: ‘Display Text’,
type: ‘string’
},
{
name: ‘grammar’,
title: ‘Grammar Type’,
type: ‘string’
}
],
// Defines a preview for the info within the Wealthy Textual content editor
preview: {
choose: {
// Selects information to go to our part
textual content: ‘displayText’,
grammar: ‘grammar’
},

// Tells the sphere which preview to make use of
part: madlibPreview,
},
}

As soon as that’s created, we are able to add it to our schemas array and use it as a sort in our Moveable Textual content blocks.

// /madlibs/studio/schemas/schema.js
// First, we should import the schema creator
import createSchema from ‘half:@sanity/base/schema-creator’

// Then import schema varieties from any plugins that may expose them
import schemaTypes from ‘all:half:@sanity/base/schema-type’

import madlib from ‘./madlib’
// Import the brand new object
import madlibField from ‘./objects/madlibField’

// Then we give our schema to the builder and supply the end result to Sanity
export default createSchema({
// We title our schema
title: ‘default’,
// Then proceed to concatenate our doc kind
// to those supplied by any plugins which might be put in
varieties: schemaTypes.concat([
// documents
madlib,
//objects
madlibField
])
})

Creating The Schema For Person-generated Madlibs

For the reason that user-generated madlibs shall be submitted from our frontend, we don’t technically want a schema for them. Nonetheless, if we create a schema, we get a straightforward approach to see all of the entries (and delete them if mandatory).

We would like the construction for these paperwork to be the identical as our madlib templates. The principle variations on this schema from our madlib schema are the title, title, and, optionally, making the fields read-only.

// /madlibs/studio/schema/userLib.js
export default {
title: ‘userLib’,
title: ‘Person Generated Madlibs’,
kind: ‘doc’,
fields: [
{
name: ‘title’,
title: ‘Title’,
type: ‘string’,
readOnly: true
},
{
title: ‘Slug’,
name: ‘slug’,
type: ‘slug’,
readOnly: true,
options: {
source: ‘title’,
maxLength: 200, // // will be ignored if slugify is set
},
},
{
title: ‘Madlib Text’,
name: ‘text’,
type: ‘array’,
readOnly: true,
of: [
{
type: ‘block’,
name: ‘block’,
of: [
{ type: ‘madlibField’ }
]
},
]
},
]
}

With that, we are able to add it to our schema.js file, and our admin is full. Earlier than we transfer on, make sure to add a minimum of one madlib template. I discovered the primary paragraph of Moby Dick labored surprisingly effectively for some humorous outcomes.

Constructing The Frontend With 11ty

To create the frontend, we’ll use 11ty. 11ty is a static website generator written in and prolonged by Node. It does the job of making HTML from a number of sources of information effectively, and with some new options, we are able to lengthen that to server-rendered pages and build-rendered pages.

Setting Up 11ty

First, we’ll have to get issues arrange.

Inside the primary madlibs listing, let’s create a brand new website listing. This listing will home our 11ty website.

Open a brand new terminal and alter the listing into the positioning listing. From there, we have to set up just a few dependencies.

// Create a brand new bundle.json
npm init -y
// Set up 11ty and Sanity utilities
npm set up @11ty/eleventy@beta @sanity/block-content-to-html @sanity/consumer

As soon as these have been put in, we’ll add a few scripts to our bundle.json

// /madlibs/website/bundle.json

“scripts”: {
“begin”: “eleventy –serve”,
“construct”: “eleventy”
},

Now that we’ve a construct and begin script, let’s add a base template for our pages to make use of and an index web page.

By default, 11ty will look in an _includes listing for our templates, so create that listing and add a base.njk file to it.

<!DOCTYPE html>
<html lang=”en”>

<head>
<meta charset=”UTF-8″>
<meta title=”viewport” content material=”width=device-width, initial-scale=1.0″>
<title>Madlibs</title>
{# Fundamental reset #}
<hyperlink rel=”stylesheet” href=”https://unpkg.com/some-nice-basic-css/world.css” />

</head>

<physique>
<nav class=”container navigation”>
<a category=”emblem” href=”/”>Madlibs</a>
</nav>

<div class=”stack container bordered”>
{# Inserts content material from a web page file and renders it as html #}
{ secure }
</div>

{% block scripts %}
{# Block to insert scripts from little one templates #}
{% endblock %}
</physique>

</html>

As soon as we’ve a template, we are able to create a web page. First, within the root of the positioning listing, add an index.html file. Subsequent, we’ll use frontmatter so as to add a bit information — a title and the structure file to make use of.


title: Madlibs
structure: ‘base.njk’

<p>Some madlibs to take your thoughts off issues. They’re saved in <a href=”https://sanity.io”>Sanity.io</a>, constructed with <a href=”https://11ty.dev”>11ty</a>, and do attention-grabbing issues with Netlify serverless features.</p>

Now you can begin 11ty by operating npm begin within the website listing.

Creating Pages From Sanity Information Utilizing 11ty Pagination

Now, we wish to create pages dynamically from information from Sanity. To do that, we’ll create a JavaScript Information file and a Pagination template.

Earlier than we dive into these information, we have to create a few utilities for working with the Sanity information.

Inside the positioning listing, let’s create a utils listing.

The primary utility we’d like is an initialized Sanity JS consumer. First, create a file named sanityClient.js within the new utils listing.

// /madlibs/website/utils/sanityClient.js’
const sanityClient = require(‘@sanity/consumer’)
module.exports = sanityClient({
// The undertaking ID
projectId: ‘<YOUR-ID>’,
// The dataset we created
dataset: ‘manufacturing’,
// The API model we wish to use
// Finest apply is to set this to as we speak’s date
apiVersion: ‘2021-06-07’,
// Use the CDN as an alternative of fetching straight from the info retailer
useCdn: true
})

Since our wealthy textual content is saved as Moveable Textual content JSON, we’d like a approach to convert the info to HTML. We’ll create a utility to do that for us. First, create a file named portableTextUtils.js within the utils listing.

For Sanity and 11ty websites, we usually will wish to convert the JSON to both Markdown or HTML. For this website, we’ll use HTML to have granular management over the output.

Earlier, we put in @sanity/block-content-to-html, which can assist us serialize the info to HTML. The bundle will work on all fundamental forms of Moveable Textual content blocks and kinds. Nonetheless, we’ve a customized block kind that wants a customized serializer.

// Initializes the bundle
const toHtml = require(‘@sanity/block-content-to-html’)
const h = toHtml.h;

const serializers = {
varieties: {
madlibField: ({ node }) => {
// Takes every node of kind madlibField
// and returns an HTML span with an id, class, and textual content
return h(‘span’, node.displayText, { id: node._key, className: ’empty’ })
}
}
}

const prepText = (information) => {
// Takes the info from a particular Sanity doc
// and creates a brand new htmlText property to comprise the HTML
// This lets us preserve the Moveable Textual content information intact and nonetheless show HTML
return {
…information,
htmlText: toHtml({
blocks: information.textual content, // Moveable Textual content information
serializers: serializers // The serializer to make use of
})
}
}

// We solely have to export prepText for our features
module.exports = { prepText }

The serializers object on this code has a varieties object. On this object, we create a specialised serializer for any kind. The important thing within the object ought to match the kind given in our information. In our case, that is madlibField. Every kind may have a operate that returns a component written utilizing hyperscript features.

On this case, we create a span with youngsters of the displayText from the present information. Later we’ll want distinctive IDs primarily based on the info’s _key, and we’ll want a category to type these. We offer these in an object because the third argument for the h() operate. We’ll use this identical serializer setup for each our madlib templates and the user-generated madlibs.

Now that we’ve our utilities, it’s time to create a JavaScript information file. First, create a _data within the website listing. On this file, we are able to add world information to our 11ty website. Subsequent, create a madlibs.js file. This file is the place our JavaScript will run to tug every madlib template. The info shall be out there to any of our templates and pages beneath the madlibs key.

// Get our utilities
const consumer = require(‘../utils/sanityClient’)
const {prepText} = require(‘../utils/portableTextUtils’)
// The GROQ question used to search out particular paperwork and
// form the output
const question = *[_type == “madlib”]{
title,
“slug”: slug.present,
textual content,
_id,
“formFields”: textual content[]{
youngsters[_type == “madlibField”]{
displayText,
grammar,
_key
}
}.youngsters[]
}

module.exports = async operate() {
// Fetch information primarily based on the question
const madlibs = await consumer.fetch(question);

// Put together the Moveable Textual content information
const preppedMadlib = madlibs.map(prepText)
// Return the total array
return preppedMadlib
}

To fetch the info, we have to get the utilities we simply created. The Sanity consumer has a fetch() technique to go a GROQ question. We’ll map over the array of paperwork the question returns to arrange their Moveable Textual content after which return that to 11ty’s information cascade.

The GROQ question on this code instance is doing many of the work for us. We begin by requesting all paperwork with a _type of madlib from our Sanity content material lake. Then we specify which information we wish to return. The info begins merely: we’d like the title, slug, wealthy textual content, and id from the doc, however we additionally wish to reformat the info right into a set of type fields, as effectively.

To try this, we create a brand new property on the info being returned: formFields. This appears on the textual content information (a Moveable Textual content array) and loops over it with the [] operator. We are able to then construct a brand new undertaking on this information like we’re doing with your complete doc with the {} operator.

Every textual content object has a youngsters array. We are able to loop by way of that, and if the merchandise matches the filter contained in the [], we are able to run one other projection on that. On this case, we’re filtering all youngsters which have a _type == “madlibField”. In different phrases, any inline block that has an merchandise with the kind we created. We want the displayText, grammar, and _key for every of those. It will return an array of textual content objects with the kids matching our filter. We have to flatten this to be an array of youngsters. To do that, we are able to add the .youngsters[] after the initiatives. It will return a flat array with simply the kids parts we’d like.

This offers us all of the paperwork in an array with simply the info we’d like (together with newly reformatted gadgets).

To make use of them in our 11ty construct, we’d like a template that may use Pagination.

Within the root of the positioning, create a madlib.njk file. This file will generate every madlib web page from the info.


structure: ‘base.njk’
pagination:
information: madlibs
alias: madlib
measurement: 1
permalink: “madlibs/{ slug }/index.html”

Within the entrance matter of this file, we specify some information 11ty can use to generate our pages:

structure
The template to make use of to render the web page.
pagination
An object with pagination info.
pagination.information
The info key for pagination to learn.
pagination.alias
A key to make use of on this file for ease.
pagination.measurement
The variety of madlibs per web page (on this case, 1 per web page to create particular person pages).
permalink
The URLs at which every of those ought to reside (might be partially generated from information).

With that information in place, we are able to specify how one can show every bit of information for an merchandise within the array.


structure: ‘base.njk’
pagination:
information: madlibs
alias: madlib
measurement: 1
permalink: “madlibs/{ slug }/index.html”

<h2>{{ madlib.title }}</h2>
<p><em>Directions:</em> Fill out this way, submit it and get your story. It is going to hopfully make little-to-no sense. Afterward, it can save you the madlib and ship it to your folks.</p>
<div class=”madlibtext”>
<a href=”#” class=”saver”>Reserve it</a>
{ secure }
</div>
<h2>Type</h2>
<type class=”madlibForm stack”>
{% for enter in madlib.formFields %}
<label>
{{ enter.displayText }} ({{ enter.grammar }})
<enter kind=”textual content” class=”libInput” title={{enter._key}}>
</label>
{% endfor %}
<button>Executed</button>
</type>

We are able to correctly format the title and HTML textual content. We are able to then use the formFields array to create a type that customers can enter their distinctive solutions.

There’s some further markup to be used in our JavaScript — a type button and a hyperlink to save lots of the finalized madlib. The hyperlink and madlib textual content shall be hidden (no peeking for our customers!).

For each madlib template, you created in your studio, 11ty will construct a singular web page. The ultimate URLs ought to appear to be this

http://localhost:8080/madlibs/the-slug-in-the-studio/

Making The Madlibs Interactive

With our madlibs generated, we have to make them interactive. We’ll sprinkle a bit JavaScript and CSS to make them interactive. Earlier than we are able to use CSS and JS, we have to inform 11ty to repeat the static information to our constructed website.

Copying Static Property To The Last Construct

Within the root of the positioning listing, create the next information and directories:

property/css/type.css — for any further styling,
property/js/madlib.js — for the interactions,
.eleventy.js — the 11ty configuration file.

When these information are created, we have to inform 11ty to repeat the property to the ultimate construct. These directions reside within the .eleventy.js configuration file.

module.exports = operate(eleventyConfig) {
eleventyConfig.addPassthroughCopy(“property/”);
}

This instructs 11ty to repeat your complete property listing to the ultimate construct.

The one mandatory CSS to make the positioning work is a snippet to cover and present the madlib textual content. Nonetheless, in order for you the entire appear and feel, you could find all of the kinds on this file.

.madlibtext {
show: none
}
.madlibtext.present {
show: block;
}

Filling In The Madlib With Person Enter And JavaScript

Any frontend framework will work with 11ty when you arrange a construct course of. For this instance, we’ll use plain JavaScript to maintain issues easy. The primary activity is to take the person information within the type and populate the generic madlib template that 11ty generated from our Sanity information.

// Connect the shape handler
const type = doc.querySelector(‘.madlibForm’)
type.addEventListener(‘submit’, completeLib);

operate showText() {
// Discover the madlib textual content within the doc
const textDiv = doc.querySelector(‘.madlibtext’)
// Toggle the category “present” to be current
textDiv.classList.toggle(‘present’)
}

// A operate that takes the submit occasion
// From the occasion, it can get the contents of the inputs
// and write them to web page and present the total textual content
operate completeLib(occasion) {
// Do not submit the shape
occasion.preventDefault();
const { goal } = occasion // The goal is the shape aspect

// Get all inputs from the shape in array format
const inputs = Array.from(goal.parts)

inputs.forEach(enter => {
// The button is an enter and we do not need that within the closing information
if (enter.kind != ‘textual content’) return
// Discover a span by the enter’s title
// These will each be the _key worth
const replacedContent = doc.getElementById(enter.title)
// Substitute the content material of the span with the enter’s worth
replacedContent.innerHTML = enter.worth
})
// Present the finished madlib
showText();
}

This performance is available in three components: attaching an occasion listener, taking the shape enter, inserting it into the HTML, after which exhibiting the textual content.

When the shape is submitted, the code creates an array from the shape’s inputs. Subsequent, it finds parts on the web page with ids that match the enter’s title — each created from the _key values of every block. It then replaces the content material of that aspect with the worth from the info.

As soon as that’s performed, we toggle the total madlib textual content to point out on the web page.

We have to add this script to the web page. To do that, we create a brand new template for the madlibs to make use of. Within the _includes listing, create a file named lib.njk. This template will lengthen the bottom template we created and insert the script on the backside of the web page’s physique.

{% extends ‘base.njk’ %}

{% block scripts %}
<script>
var pt = { secure }
var information = {
libId: {{ madlib._id }},
libTitle: {{ madlib.title }}
}
</script>
<script src=”/property/js/madlib.js”></script>
{% endblock %}

Then, our madlib.njk pagination template wants to make use of this new template for its structure.


structure: ‘lib.njk’
pagination:
information: madlibs
alias: madlib
measurement: 1
permalink: “madlibs/{ slug }/index.html”

// web page content material

We now have a functioning madlib generator. To make this extra sturdy, let’s enable customers to save lots of and share their accomplished madlibs.

Saving A Person Madlib To Sanity With A Netlify Perform

Now that we’ve a madlib exhibited to the person, we have to create the hyperlink for saving ship the knowledge to Sanity.

To try this, we’ll add some extra performance to our front-end JavaScript. However, first, we have to add some extra information pulled from Sanity into our JavaScript, so we’ll add a few new variables within the scripts block on the lib.njk template.

{% extends ‘base.njk’ %}

{% block scripts %}
<script>
// Moveable Textual content information
var pt = { secure }
var information = {
libId: {{ madlib._id }},
libTitle: {{ madlib.title }}
}
</script>
<script src=”/property/js/madlib.js”></script>
{% endblock %}

We are able to write a script to ship it and the user-generated solutions to a serverless operate to ship to Sanity with that further information.

// /madlibs/website/property/js/madlib.js

// … completeLib()

async operate saveLib(occasion) {
occasion.preventDefault();

// Return an Map of ids and content material to show into an object
const blocks = Array.from(doc.querySelectorAll(‘.empty’)).map(merchandise => {
return [item.id, { content: item.outerText }]
})
// Creates Object prepared for storage from blocks map
const userContentBlocks = Object.fromEntries(blocks);

// Codecs the info for posting
const finalData = {
userContentBlocks,
pt, // From nunjucks on web page
…information // From nunjucks on web page
}

// Runs the publish information operate for createLib
postData(‘/.netlify/features/createLib’, finalData)
.then(information => {
// When publish is profitable
// Create a div for the ultimate hyperlink
const landingZone = doc.createElement(‘div’)
// Give the hyperlink a category
landingZone.className = “libUrl”
// Add the div after the saving hyperlink
saver.after(landingZone)
// Add the brand new hyperlink contained in the touchdown zone
landingZone.innerHTML = <a href=”/userlibs/${information._id}/” class=”savedUrl”>Your url is /userlibs/${information._id}/</a>

}).catch(error => {
// When errors occur, do one thing with them
console.log(error)
});
}

async operate postData(url = ”, information = {}) {
// A wrapper operate for normal JS fetch
const response = await fetch(url, {
technique: ‘POST’,
mode: ‘cors’,
cache: ‘no-cache’,
credentials: ‘same-origin’,
headers: {
‘Content material-Sort’: ‘utility/json’
},
physique: JSON.stringify(information)
});
return response.json(); // parses JSON response into native JavaScript objects
}

We add a brand new occasion listener to the “Save” hyperlink in our HTML.

The saveLib operate will take the info from the web page and the user-generated information and mix them in an object to be dealt with by a brand new serverless operate. The serverless operate must take that information and create a brand new Sanity doc. When creating the operate, we wish it to return the _id for the brand new doc. We use that to create a singular hyperlink that we add to the web page. This hyperlink shall be the place the newly generated web page shall be.

Setting Up Netlify Dev

To make use of Netlify Capabilities, we’ll have to get our undertaking arrange on Netlify. We would like Netlify to construct and serve from the positioning listing. To provide Netlify this info, we have to create a netlify.toml file on the root of your complete undertaking.

[build]
command = “npm run construct” # Command to run
features = “features” # Listing we retailer the features
publish = “_site” # Folder to publish (11ty mechanically makes the _site folder
base = “website” # Folder that’s the root of the construct

To develop these domestically, it’s useful to put in Netlify’s CLI globally.

npm set up -g netlify-cli

As soon as that’s put in, you’ll be able to run netlify dev in your undertaking. It will take the place of operating your begin NPM script.

The CLI will run you thru connecting your repository to Netlify. As soon as it’s performed, we’re able to develop our first operate.

Creating A Perform To Save Madlibs To Sanity

Since our TOML file units the features listing to features, we have to create the listing. Contained in the listing, make a createLib.js file. This would be the serverless operate for making a madlib within the Sanity information retailer.

The usual Sanity consumer we’ve been utilizing is read-only. To provide it write permissions, we have to reconfigure it to make use of an API learn+write token. To generate a token, log into the undertaking dashboard and go to the undertaking settings in your madlibs undertaking. Within the settings, discover the Tokens space and generate a brand new token with “Editor” permissions. When the token is generated, save the string to Netlify’s atmosphere variables dashboard with the title SANITY_TOKEN. Netlify Dev will mechanically pull these atmosphere variables into the undertaking whereas operating.

To reconfigure the consumer, we’ll require the file from our utilities, after which run the .config() technique. It will allow us to set any configuration worth for this particular use. We’ll set the token to the brand new atmosphere variable and set useCdn to false.

// Sanity JS Shopper
// The construct consumer is read-only
// To make use of to jot down, we have to add an API token with correct permissions
const consumer = require(‘../utils/sanityClient’)
consumer.config({
token: course of.env.SANITY_TOKEN,
useCdn: false
})

The fundamental construction for a Netlify operate is to export a handler operate that’s handed an occasion and returns an object with a standing code and string physique.

// Grabs native env variables from .env file
// Not mandatory if utilizing Netlify Dev CLI
require(‘dotenv’).config()

// Sanity JS Shopper
// The construct consumer is read-only
// To make use of to jot down, we have to add an API token with correct permissions
const consumer = require(‘../utils/sanityClient’)
consumer.config({
token: course of.env.SANITY_TOKEN,
useCdn: false
})

// Small ID creation bundle
const { nanoid } = require(‘nanoid’)

exports.handler = async (occasion) => {
// Get information off the occasion physique
const {
pt,
userContentBlocks,
id,
libTitle
} = JSON.parse(occasion.physique)

// Create new Moveable Textual content JSON
// from the previous PT and the person submissions
const newBlocks = findAndReplace(pt, userContentBlocks)

// Create new Sanity doc object
// The doc’s _id and slug are primarily based on a singular ID from nanoid
const docId = nanoid()
const doc = {
_type: “userLib”,
_id: docId,
slug: { present: docId },
madlib: id,
title: ${libTitle} creation,
textual content: newBlocks,
}

// Submit the brand new doc object to Sanity
// Return the response again to the browser
return consumer.create(doc).then((res) => {
// Log the success into our operate log
console.log(Userlib was created, doc ID is ${res._id})
// return with a 200 standing and a stringified JSON object we get from the Sanity API
return { statusCode: 200, physique: JSON.stringify(doc) };
}).catch(err => {
// If there’s an error, log it
// and return a 500 error and a JSON string of the error
console.log(err)
return {
statusCode: 500, physique: JSON.stringify(err)
}
})
}

// Perform for modifying the Moveable Textual content JSON
// pt is the unique moveable Textual content
// mods is an object of modifications to make
operate findAndReplace(pt, mods) {
// For every block object, verify to see if a mod is required and return an object
const newPT = pt.map((block) => ({
…block, // Insert all present information
youngsters: block.youngsters.map(span => {
// For each merchandise in youngsters, see if there is a modification on the mods object
// If there may be, set modContent to the brand new content material, if not, set it to the unique textual content
const modContent = mods[span._key] ? mods[span._key].content material : span.textual content
// Return an object with all the unique information, and a brand new property
// displayText to be used within the frontends
return {
…span,
displayText: modContent
}
})
}))
// Return the brand new Moveable Textual content JSON
return newPT
}

The physique is the info we simply submitted. For ease, we’ll destructure the info off the occasion.physique object. Then, we have to evaluate the unique Moveable Textual content and the person content material we submitted and create the brand new Moveable Textual content JSON that we are able to undergo Sanity.

To try this, we run a discover and substitute operate. This operate maps over the unique Moveable Textual content and for each little one within the blocks, substitute its content material with the corresponding information from the modfications object. If there isn’t a modification, it can retailer the unique textual content.

With modified Moveable Textual content in hand, we are able to create a brand new object to retailer as a doc within the Sanity content material lake. Every doc wants a singular identifier (which we are able to use the nanoid NPM bundle to create. We’ll additionally let this newly created ID be the slug for consistency.

The remainder of the info is mapped to the right key in our userLib schema we created within the studio and submitted with the authenticated consumer’s .create() technique. When success or failure returns from Sanity, we go that alongside to the frontend for dealing with.

Now, we’ve information being saved to our Sanity undertaking. Go forward and fill out a madlib and submit. You may view the creation within the studio. These hyperlinks that we’re producing don’t work but, although. That is the place 11ty Serverless is available in.

Setting Up 11ty Serverless

You could have seen once we put in 11ty that we used a particular model. That is the beta of the upcoming 1.0 launch. 11ty Serverless is without doubt one of the huge new options in that launch.

Putting in The Serverless Plugin

11ty Serverless is an included plugin that may be initialized to create all of the boilerplate for operating 11ty in a serverless operate. To stand up and operating, we have to add the plugin to our .eleventy.js configuration file.

const { EleventyServerlessBundlerPlugin } = require(“@11ty/eleventy”);

module.exports = operate (eleventyConfig) {
eleventyConfig.addPassthroughCopy(“property/”);

eleventyConfig.addPlugin(EleventyServerlessBundlerPlugin, {
title: “userlibs”, // the title to make use of for the features
functionsDir: “./features/”, // The features listing
copy: [“utils/”], // Any information that must be copied to make our scripts work
excludeDependencies: [“./_data/madlibs.js”] // Exclude any information you do not wish to run
});
};

After creating this file, restart 11ty by rerunning netlify dev. On the subsequent run, 11ty will create a brand new listing in our features listing named userlibs (matching the title within the serverless configuration) to accommodate every part it must need to run in a serverless operate. The index.js file on this listing is created if it doesn’t exist, however any adjustments you make will persist.

We have to make one small change to the tip of this file. By default, 11ty Serverless will initialize utilizing customary serverless features. It will run the operate on each load of the route. That’s an costly load for content material that may’t be modified after it’s been generated. As a substitute, we are able to change it to make use of Netlify’s On-Demand Builders. It will construct the web page on the primary request and cache the end result for any later requests. This cache will persist till the subsequent construct of the positioning.

To replace the operate, open the index.js file and alter the ending of the file.

// Remark this line out
exports.handler = handler

// Uncomment these traces
const { builder } = require(“@netlify/features”);
exports.handler = builder(handler);

Since this file is utilizing Netlify’s features bundle, we additionally want to put in that bundle.

npm set up @netlify/features

Creating A Information File For Person-generated Madlibs

Now that we’ve an On-Demand Builder, we have to pull the info for user-generated madlibs. We are able to create a brand new JavaScript information file within the _data file named userlibs.js. Like our madlibs information file, the file title would be the key to get this information in our templates.

// /madlibs/website/_data/userlibs.js

const consumer = require(‘../utils/sanityClient’)
const {prepText} = require(‘../utils/portableTextUtils’)

const question = *[_type == “userLib”]{
title,
“slug”: slug.present,
textual content,
_id
}

module.exports = async operate() {
const madlibs = await consumer.fetch(question);
// Defend in opposition to no madlibs returning
if (madlibs.size == 0) return {“404”: {}}

// Run by way of our moveable textual content serializer
const preppedMadlib = madlibs.map(prepText)

// Convert the array of paperwork into an object
// Every merchandise within the Object may have a key of the merchandise slug
// 11ty’s Pagination will create pages for every one
const mapLibs = preppedMadlib.map(merchandise => ([item.slug, item]))
const objLibs = Object.fromEntries(mapLibs)
return objLibs
}

This information file is just like what we wrote earlier, however as an alternative of returning the array, we have to return an object. The thing’s keys are what the serverless bundle will use to tug the proper madlib on request. In our case, we’ll make the merchandise’s slug the important thing for the reason that serverless route shall be searching for a slug.

Creating A Pagination Template That Makes use of Serverless Routes

Now that the plugin is prepared, we are able to create a brand new pagination template to make use of the generated operate.

Within the root of our website, add a userlibs.njk template. This template shall be just like the madlibs.njk template, however it can use completely different information with none interactivity.


structure: ‘base.njk’
pagination:
information: userLibs
alias: userlib
measurement: 1
serverless: eleventy.serverless.path.slug

permalink:
userlibs: “/userlibs/:slug/”

<h2>{{ userlib.title }}</h2>
<div>
{ secure }
</div>

On this template, we use base.njk to keep away from together with the JavaScript. We specify the brand new userlibs information for pagination.

To tug the proper information, we have to specify what the lookup key shall be. On the pagination object, we do that with the serverless property. When utilizing serverless routes, we get entry to a brand new object: eleventy.serverless. On this object, there’s a path object that comprises info on what URL the person requested. On this case, we’ll have a slug property on that object. That should correspond to a key on our pagination information.

To get the slug on our path, we have to add it to the permalink object. 11ty Serverless permits for a couple of route for a template. The route’s key must match the title supplied within the .eleventy.js configuration. On this case, it must be userlibs. We specify the static /userlibs/ begin to the trail after which add a dynamic aspect: :slug/. This slug shall be what will get handed to eleventy.serverless.path.slug.

Now, the hyperlink that we created earlier by submitting a madlib to Sanity will work.

Subsequent Steps

Now we’ve a madlib generator that saves to a knowledge retailer. We construct solely the mandatory pages to permit a person to create a brand new madlib. Once they create one, we make these pages on-demand with 11ty and Netlify Capabilities. From right here, we are able to lengthen this additional.

Statically construct the user-generated content material in addition to render them on request.
Create a counter for the overall variety of madlibs saved by every madlib template.
Create an inventory of phrases customers use by components of speech.

When you’ll be able to statically construct AND dynamically render, what types of functions does this open up?

    About Marketing Solution Australia

    We are a digital marketing company with a focus on helping our customers achieve great results across several key areas.

    Request a free quote

    We offer professional SEO services that help websites increase their organic search score drastically in order to compete for the highest rankings even when it comes to highly competitive keywords.

    Subscribe to our newsletter!

    More from our blog

    See all posts

    Leave a Comment