4th week of 2021

Published on

Episerver + TinyMCE + React, lazy vs greedy quantifiers in regular expressions, Tailwind-in-JS library (Twind), and more.

Table of contents

👨‍💼 Work

Episerver + TinyMCE + React = uh oh!

Planned how to mount React components to a <div> whose contents are defined using the dangerouslySetInnerHTML prop. Sounds ugly, and it is, but hear me out:

We use TinyMCE for rich text editing in our Episerver (.NET CMS) sites. Episerver allows drag-and-dropping "blocks" (reusable pieces of content) into TinyMCE fields. By default, blocks are rendered as empty divs, like this (simplified example):

<p>Normal content</p>
<div data-epi-block-id="123"></div>
<p>
More normal content.
Block inside a paragraph:
<div data-epi-block-id="456"></div>
And more text.
</p>

Now, I could render the HTML as-is, retrieve the blocks' data using Ajax requests after the component has been mounted, and then mount other React components to the <div>s. But I don't want to, because that would be slow and incur an extra HTTP request per each block.

I'm thinking of including the blocks' data in the HTML before sending it to the front-end:

<p>Normal content</p>
<div data-epi-block='{ "id": 123, "blockType": "FooBlock", "title": "Hello block", ... }'></div>
<p>
More normal content.
Block inside a paragraph:
<div data-epi-block='{ "id": 456, "blockType": "BarBlock", "title": "Another block", ... }'></div>
And more text.
</p>

Then I could use JSON.parse() to turn those JSON attributes into props objects. Mounting React components to those <div>s could be done as suggested in these Stack Overflow answers:

Like I said: ugly! And still just a theory. But necessary. We shall see later if this feasible.

👨‍🚀 Personal

New fonts on my website + more tweaking

  • Tweaked styles.

  • Added fonts: Inter for body text and JetBrains Mono for inline code and code blocks. Both are lovely!

  • Added more stuff to the home page.

    Last week I set up Plausible Analytics on my website. The data from the first week shows that the home page is the most visited page (30 visitors, though I wonder how many of those are me, haha), and that the bounce rate (how many people leave without visiting other pages) of the home page is 73%. I.e. most visitors leave immediately after arriving on my website.

    Based on this, I added some links to the home page, like a link to the latest blog post. We'll see if that has any effects on the bounce rate.

👨‍🎓 Learnings

JavaScript: formatting lists with Intl.ListFormat

Intl.ListFormat enables language-sensitive list formatting. Example:

const list = ['Ham', 'Spam', 'Eggs']

new Intl.ListFormat('en-US', {
style: 'long',
type: 'conjunction',
}).format(list)
//=> Ham, Spam, and Eggs

new Intl.ListFormat('en-US', {
style: 'short',
type: 'disjunction',
}).format(list)
//=> Ham, Spam, or Eggs

new Intl.ListFormat('en-GB', {
style: 'long',
type: 'conjunction',
}).format(list)
//=> Ham, Spam and Eggs

new Intl.ListFormat('en-GB', {
style: 'short',
type: 'disjunction',
}).format(list)
//=> Ham, Spam or Eggs

Notice how the en-US locale uses Oxford commas and en-GB does not.

Unfortunately, Intl.ListFormat isn't currently supported by Safari or iOS Safari.

I had previously wondered why Stack Overflow's short links include my user ID. For example, the short link to the question Is there a way to alphabetize package.json without installing a package? looks like this:

https://stackoverflow.com/q/34438465/1079869

q = question ("a" would be answer)
34438465 = question ID
1079869 = my user ID

The user ID can be removed from the URL and it'll still work fine. But if you leave the user ID, you can earn badges if the link is visited from multiple unique IP addresses. The downside is that the links are not anonymous (because they include your user ID), which can be problematic in some cases.

Regular expressions: lazy vs greedy quantifiers

Lazy vs greedy quantifiers in regular expressions was a somewhat familiar concept to me, but I had never studied them properly. Now I did.

  • Quantifiers are greedy by default: *, +, ?, {n}, {n,} and {n,m} are greedy quantifiers. They keep looking until the condition is not satisfied.
  • Quantifiers can be made lazy by appending a question mark: *?, +?, ??, {n}?, {n,}? and {n,m}? are lazy quantifiers. They stop looking when the condition is satisfied.

For example, getting the name of an HTML tag:

const html = '<div>foo</div>'

// Greedy
html.match(/<.+>/)[0]
//=> '<div>foo</div>'

// Lazy
html.match(/<.+?>/)[0]
//=> '<div>'

As you can see, the greedy quantifier is too greedy in this case, whereas the lazy quantifier matches just enough but not too much. It's like smart laziness.

Sometimes an alternative is to use a negated character class:

html.match(/<[^>]+>/)[0]
//=> '<div>'

The result is the same as when using a lazy quantifier, but the performance is better because "the negated character class can only match one way for a given input."

🕵️‍♂️ Cool stuff

Twind: Tailwind-in-JS

Twind is "the smallest, fastest, most feature complete Tailwind-in-JS solution in existence." Looks promising!

Naming cheatsheet

Naming cheatsheet: "comprehensive language-agnostic guidelines on variables naming." There are many cheatsheets/guidelines like this. I like this one because it makes sense and is short, clear and language-agnostic.

Variable fonts

Variable fonts are cool! From the linked page:

Variable fonts are an evolution of the OpenType font specification that enables many different variations of a typeface to be incorporated into a single file, rather than having a separate font file for every width, weight, or style. They let you access all the variations contained in a given font file via CSS and a single @font-face reference.

Variable fonts' browser support is also good (supported by all modern browsers).

I'm using the Inter font on this website. It has a variable version, so I'm serving only a single woff2 file. (I just noticed that it weights over 70KB, so serving multiple non-variable woff2 files might be a better choice if using HTTP2.)

💁‍♂️ More Weekly log entries

Next week: 5th week of 2021

Previous week: 3rd week of 2021